Node.js 是一个开源与跨平台的 JavaScript 运行时环境,通过 Node.js 开发者可以在浏览器之外运行 JavaScript 代码,使得 JS 也拥有了开发后端项目的能力。同时 Node.js 运行 V8 JavaScript 引擎(Google Chrome 的内核),这意味着 Node.js 拥有足够优秀的的性能。
![logo https://wumanhoblogimg.obs.cn-south-1.myhuaweicloud.com/images/nodejslogo.png](/svg/loading.min.svg)
构建基础框架 ⚒️
先构建出一个基础 Web 服务器,再完善功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const http = require('http')
const fs = require('fs')
const url = require('url')
const port = process.argv[2] || 8888;
const server = http.createServer((request, response) => {
/*... ...*/
})
server.listen(port, hostname, () => {
console.log(`服务器启动成功,请访问: http://${hostname}:${port}/`)
})
|
到目前为止,我们做了以下几件事,首先应用了一些必须的模块,Node.js 具有丰富的标准库,包括对网络的完善支持。
1
2
3
|
const http = require('http') //用于实现 HTTP 服务器或客户端
const fs = require('fs') //用于操作文件系统
const url = require('url') //用于处理与解析 URL
|
如果用户没有指定端口号,则默认端口号为 8888
1
|
const port = process.argv[2] || 8888;
|
创建一个服务器
1
2
3
|
const server = http.createServer((request, response) => {
/*... ...*/
})
|
启动端口监听
1
2
3
|
server.listen(port, hostname, () => {
console.log(`服务器启动成功,请访问: http://${hostname}:${port}/`)
})
|
实现服务器功能 🔧
可以将整个服务器代码分成几个部分去理解:
- 获取查询参数;
- 设置响应参数;
- 路由查询;
- 发送响应;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
const server = http.createServer(function(request, response){
let parsedUrl = url.parse(request.url, true)
let pathWithQuery = request.url
let queryString = ''
if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
let path = parsedUrl.pathname
let query = parsedUrl.query
let method = request.method
response.statusCode = 200
const filePath = path === '/' ? '/index.html' : path
const index = filePath.lastIndexOf('.')
const suffix = filePath.substring(index)
const fileTypes = {
'.html':'text/html',
'.css':'text/css',
'.js':'text/javascript',
'.png':'image/png',
'.jpg':'image/jpeg'
}
response.setHeader('Content-Type',
`${fileTypes[suffix] || 'text/html'};charset=utf-8`)
let content
try{
content = fs.readFileSync(`./public${filePath}`)
}catch(error){
content = '文件不存在'
response.statusCode = 404
}
response.write(content)
response.end()
})
|
获取查询参数 📬
获取用户请求的各种信息,方便后面使用,包括路径、请求方法、请求参数等等。本示例没有实现查询参数对应的功能,只是列举比较常用的请求信息,也可以根据情况只获取所需的即可,不必全部获取。
1
2
3
4
5
6
7
8
9
10
|
let parsedUrl = url.parse(request.url, true) //获取 url 对象
let pathWithQuery = request.url //获取用户请求路径(带请求参数) 字符串
//获取查询参数字符串
let queryString = ''
if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
let path = parsedUrl.pathname //获取用户请求路径(不带请求参数)字符串
let query = parsedUrl.query //获取查询参数对象
let method = request.method //获取请求方法
|
设置响应 HTTP 状态码
1
|
response.statusCode = 200
|
初始化首页,如果用户没有指定具体访问路径,自动跳转到 index.html,filePath 也是不带查询参数的用户请求路径。
1
|
const filePath = path === '/' ? '/index.html' : path
|
设置响应参数 📝
这一步主要目标是根据用户请求的资源位置,返回对应的 Content-Type,返回合适的数据格式。
获取后缀
1
2
|
const index = filePath.lastIndexOf('.')
const suffix = filePath.substring(index)
|
实现一个 fileType 哈希表,根据获取到的后缀,设置 Content-Type 格式
1
2
3
4
5
6
7
8
9
10
11
|
//文件类型哈希表
const fileTypes = {
'.html':'text/html',
'.css':'text/css',
'.js':'text/javascript',
'.png':'image/png',
'.jpg':'image/jpeg'
}
//设置响应头,如果用户请求的类型不属于上述类型,Content-Type 默认为 text/html
response.setHeader('Content-Type',
`${fileTypes[suffix] || 'text/html'};charset=utf-8`)
|
路由查询 🤔
这一步将会根据用户查询的资源路径,读取对应的静态资源返回,如果找不到对应资源,则设置状态码为 404,返回文件不存在提示。
1
2
3
4
5
6
7
|
let content
try{
content = fs.readFileSync(`./public${filePath}`)
}catch(error){
content = '文件不存在'
response.statusCode = 404
}
|
发送响应 📨
最后,将响应返回,并关闭连接。
1
2
|
response.write(content)
response.end()
|
(完)
参考 🌻
Node.js API文档