# Node服务搭建
Node搭建服务器主要是利用http请求模块和fs文件系统模块进行处理,http启动一个服务,通过拦截浏览器访问的所有请求进行返回相应数据。平时我们访问一个网站,我们只关注Ajax接口请求,其实,不论我们访问的html、css、js文件还是媒体资源其实都是响应,都要通过服务器进行处理返回对应内容。我们从头开始搭建一个简易Node服务器,来搞明白服务端是如何处理各种服务请求进行构建网站的。
# 初始化项目
创建一个项目文件夹来搭建Node服务,通过npm init来初始化项目,初始化好在该文件下创建一个app.js文件当做服务入口文件。然后在package.json文件中配置服务运行命令。
// package.json
{
"name": "node_tem",
"version": "1.0.0",
"description": "node项目",
"main": "index.js",
"scripts": {
"dev": "node app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"art-template": "^4.13.2"
},
"devDependencies": {
"nodemon": "^3.1.7"
}
}
我们在app.js中启动一个简单的服务
// app.js
var http = require('http');
var server = http.createServer();
server.on('request', function (req, res) {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end('<h1>Hello world!</h1>');
})
server.listen(3000, function () {
console.log('server is running...')
})
然后,在终端执行下面命令服务就跑起来了。
npm run dev
# 项目结构设计
├── public # 资源文件
│ ├── css # css文件
│ ├── imgs # 图片
│ ├── js # js
│ └── lib # 资源文件
├── views # 页面模板文件
│ ├── common # 公共模板
│ │ ├── header.html # 项目图片
│ │ └── footer.html # 公共less/sass文件
│ ├── index.html # 首页模板
│ ├── post.html # 其他页面
│ └── 404.4html # 404页面
├── .gitignore # git忽略
├── app.js # 服务入口文件
├── nodemon.json # 文件监听
├── package.json # 包管理
├── README.md
# 动态监听文件
node服务启动后,如果更改文件,需要重新执行启动命令才会生效,每次重启太麻烦了,我们使用nodemon插件来自动监听文件变化更新服务。
安装:
npm i nodemon -D
在根目录创建nodemon.json文件:
{
"restartable": "rs",
"ignore": [".git", ".svn", "node_modules/**/node_modules"],
"verbose": true,
"execMap": {
"js": "node --harmony"
},
"watch": [],
"env": {
"NODE_ENV": "development"
},
"ext": "js json njk css js "
}
在package.json文件添加启动命令:
{
"name": "node_tem",
"version": "1.0.0",
"description": "node项目",
"main": "index.js",
"scripts": {
"start": "nodemon app.js",
},
"author": "",
"license": "ISC",
"dependencies": {
"art-template": "^4.13.2"
},
"devDependencies": {
"nodemon": "^3.1.7"
}
}
然后执行npm run start命令就可以自动监听文件改变了。
# 响应文件内容
在浏览器输入一个地址,响应对应的页面,简单的HTML内容我们可以在 res.end() 中直接返回,如果想返回一个完整的HTML页面就需要借助 fs 模块读取文件内容,返回给客户端进行响应。
// app.js
var http = require('http')
var fs = require('fs')
var server = http.createServer()
server.on('request', function (req, res) {
// 读取html模板渲染页面
fs.readFile('./views/index.html', function (err, data) {
if (err) {
return res.end('404 Not Fond')
}
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(data)
})
})
server.listen(3000, function () {
console.log('server is running...')
})
html模板返回内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>tpl模板</title>
</head>
<body>
<div class="index">
<div class="index-header">
<h1>大家好,我叫张三</h1>
</div>
<div class="index-wrap">111</div>
</div>
</body>
</html>
# 区分响应路由
因为服务可以监听到所有请求,不论是静态资源还是页面路由。在根据响应进行返回内容时就要对响应进行区分,大概分为三大类,页面路由、接口请求、静态资源,根据不同的请求URL返回不同的资源。
我们可以借助 url 模块来获取请求的url,一般页面路由和请求单独区分出来来响应每个请求,静态资源只需要判断是否是public文件夹下的资源,就直接读取返回,如果没有对应的返回就响应404页面。
// app.js
var http = require('http')
var fs = require('fs')
// url模块的parse()方法可以解析url地址为一个json数据
var url = require('url')
var server = http.createServer()
server.on('request', function (req, res) {
// 获取url对象
var pathObj = url.parse(req.url, true)
var pathName = pathObj.pathname // 获取路由
console.log(pathName)
if (pathName === '/' || pathName === '/index.html') {
// 首页
} else if (pathName === '/pinglun') {
// 接口路由
} else if (pathName.indexOf('/public') === 0) {
// 静态资源
} else {
// 其他错误地址
fs.readFile('./views/404.html', function (err, data) {
if (err) {
return res.end('404 Not Found')
}
res.end(data)
})
}
})
server.listen(3000, function () {
console.log('server is running...')
})
# 静态资源使用
在响应的HTML文件中引入public下的CSS文件或者图片直接加载是不生效的,因为这些静态资源也是一个请求,如果我们没有做对应的请求响应是加载不到的,所以要对每一个静态资源做请求响应。我们把这些静态文件统一放在public文件夹下,只需要监听请求地址包含public目录就返回对应的文件内容就行。
var http = require('http')
var fs = require('fs')
// url模块的parse()方法可以解析url地址为一个json数据
var url = require('url')
var server = http.createServer()
server.on('request', function (req, res) {
// 获取url对象
var pathObj = url.parse(req.url, true)
var pathName = pathObj.pathname // 获取路由
console.log(pathName)
if (pathName === '/' || pathName === '/index.html') {
// 首页
// 读取html模板渲染页面
fs.readFile('./views/index.html', function (err, data) {
if (err) {
return res.end('404 Not Fond')
}
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(data)
})
} else if (pathName.indexOf('/public') === 0) {
// 读取静态文件,这里要单独配置才能读取静态文件
// 把public文件下的静态资源全部开放出去
fs.readFile('.' + pathName, function (err, data) {
if (err) {
return res.end('404 Not Found')
}
res.end(data)
})
} else {
// 其他
fs.readFile('./views/404.html', function (err, data) {
if (err) {
return res.end('404 Not Found')
}
res.end(data)
})
}
})
server.listen(3000, function () {
console.log('server is running...')
})
如果是其他文件夹下的文件也可以做同样处理。
# HTML模板引擎
纯原生HTML进行数据渲染写的话会很不方便,可以借助和Vue类似的模板引擎来开发。这里我们使用 art-template 模板引擎。art-template 不仅可以在浏览器中使用,也可以在node中使用。
下载插件:
npm i art-template
在app.js中引入插件:
// app.js
var http = require('http')
var fs = require('fs')
// 引入art-template
var template = require('art-template')
// url模块的parse()方法可以解析url地址为一个json数据
var url = require('url')
var server = http.createServer()
server.on('request', function (req, res) {
// 获取url对象
var pathObj = url.parse(req.url, true)
var pathName = pathObj.pathname // 获取路由
console.log(pathName)
if (pathName === '/tmp.html') {
// 读取html模板渲染页面
fs.readFile('./views/tmp.html', function (err, data) {
if (err) {
return res.end('404 Not Fond')
}
// 使用模板引擎
var htmlStr = data.toString()
var htmlRet = template.render(htmlStr, {
name: 'jack',
age: 19,
hobby: 'dance'
})
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(htmlRet)
})
}
})
server.listen(3000, function () {
console.log('server is running...')
})
在HTML中使用:
// tmp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>模板引擎</title>
</head>
<body>
<div class="index">
<p>大家好,我叫{{name}}</p>
<p>我今年{{age}}岁</p>
<p>我喜欢{{hobby}}</p>
</div>
</body>
</html>
# 表单提交
这里表单提交还是很原始的form表单提交,只做简单演示GET请求,提交的action地址自定义。
// app.js
var http = require('http')
var fs = require('fs')
var template = require('art-template')
// url模块的parse()方法可以解析url地址为一个json数据
var url = require('url')
var server = http.createServer()
// 渲染数据
var comments = [
{
name: '张三',
message: '你好,我是张三',
time: '2020/01/22'
}
]
server.on('request', function (req, res) {
// 获取url对象
var pathObj = url.parse(req.url, true)
var pathName = pathObj.pathname // 获取路由
if (pathName === '/pinglun') {
// 表单提交,获取数据
var comment = pathObj.query
comment.time = (new Date()).toLocaleDateString()
comments.unshift(comment)
// 获取数据后通过服务器让页面重定向到首页更新数据
// 1、状态码设置为 302 临时重定向
// statusCode
// 2、在响应头中告诉客户端往哪儿重定向
// setHeader
res.statusCode = 302
res.setHeader('Location', '/')
res.end()
}
})
server.listen(3000, function () {
console.log('server is running...')
})
在HTML中提交form表单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>发表留言</title>
</head>
<body>
<div class="index">
<form action="/pinglun" method="POST">
<div class="form-group">
<label for="name">你的名字</label>
<input type="input" name="name" class="form-control" id="name" required minlength="2" maxlength="10" placeholder="name" />
</div>
<div class="form-group">
<label for="textarea">留言内容</label>
<textarea name="message" class="form-control" rows="5" class="form-control" id="textarea" required minlength="3" maxlength="20"></textarea>
</div>
<button type="submit" class="btn btn-default">发表</button>
</form>
</div>
</body>
</html>
# 项目部署
搭建好的项目可以直接拷贝到云服务器上,和本地开启服务一样运行,并把云服务器对应的端口放开,在公网上就可以被访问到了。
参考链接:服务器使用教程