共计 3336 个字符,预计需要花费 9 分钟才能阅读完成。
Node.js
是 JavaScript
根底上倒退起来的语言,所以前端开发者应该天生就会一点。个别咱们会用它来做 CLI 工具
或者 Web 服务器
,做Web 服务器
也有很多成熟的框架,比方 Express
和Koa
。然而 Express
和Koa
都是对 Node.js
原生 API
的封装,所以其实不借助任何框架,只用原生 API
咱们也能写一个 Web 服务器
进去。本文要讲的就是不借助框架,只用原生 API
怎么写一个 Web 服务器
。因为在我的打算中,前面会写Express
和Koa
的源码解析,他们都是应用原生 API 来实现的。所以本文其实是这两个源码解析的前置常识,能够帮咱们更好的了解 Express
和Koa
这种框架的意义和源码。本文仅为阐明原生 API 的应用办法,代码较丑,请不要在理论工作中模拟!
本文可运行代码示例曾经上传 GitHub,大家能够拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/Node.js/HttpServer
Hello World
要搭建一个简略的 Web 服务器
,应用原生的http
模块就够了,一个简略的 Hello World
程序几行代码就够了:
const http = require('http')
const port = 3000
const server = http.createServer((req, res) => {
res.statusCode = 200
res.setHeader('Content-Type', 'text/plain')
res.end('Hello World')
})
server.listen(port, () => {console.log(`Server is running on http://127.0.0.1:${port}/`)
})
这个例子就很简略,间接用 http.createServer
创立了一个服务器,这个服务器也没啥逻辑,只是在拜访的时候返回 Hello World
。服务器创立后,应用server.listen
运行在 3000
端口就行。
这个例子的确简略,然而他貌似除了输入一个 Hello World
之外,啥也干不了,离咱们个别应用的 Web 服务器
还差了很远,次要是差了这几块:
- 不反对
HTTP
动词,比方GET
,POST
等- 不反对路由
- 没有动态资源托管
- 不能长久化数据
后面三点是一个 Web 服务器
必备的根底性能,第四点是否须要要看状况,毕竟目前很多 Node
的Web 服务器
只是作为一个中间层,真正跟数据库打交道做长久化的还是各种微服务,然而咱们也应该晓得长久化怎么做。
所以上面咱们来写一个真正能用的Web 服务器
,也就是说把后面缺的几点都补上。
解决路由和 HTTP 动词
后面咱们的那个 Hello World
也不是齐全不能用,因为代码地位还是得在 http.createServer
外面,咱们就在外面增加路由的性能。为了跟前面的动态资源做辨别,咱们的 API 申请都以 /api
结尾。要做路由匹配也不难,最简略的就是间接用 if
条件判断就行。为了能拿到申请地址,咱们须要应用 url
模块来解析传过来的地址。而 Http
动词间接能够用 req.method
拿到。所以 http.createServer
革新如下:
const url = require('url');
const server = http.createServer((req, res) => {
// 获取 url 的各个局部
// url.parse 能够将 req.url 解析成一个对象
// 外面蕴含有 pathname 和 querystring 等
const urlObject = url.parse(req.url);
const {pathname} = urlObject;
// api 结尾的是 API 申请
if (pathname.startsWith('/api')) {
// 再判断路由
if (pathname === '/api/users') {
// 获取 HTTP 动词
const method = req.method;
if (method === 'GET') {
// 写一个假数据
const resData = [
{
id: 1,
name: '小明',
age: 18
},
{
id: 2,
name: '小红',
age: 19
}
];
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(resData));
return;
}
}
}
});
当初咱们拜访 /api/users
就能够拿到用户列表了:
反对动态文件
下面说了 API
申请是以 /api
结尾,也就是说不是以这个结尾的能够认为都是动态文件,不同文件有不同的 Content-Type
,咱们这个例子外面临时只反对一种.jpg
吧。其实就是给咱们的 if (pathname.startsWith('/api'))
加一个 else
就行。返回动态文件须要:
- 应用
fs
模块读取文件。- 返回文件的时候依据不同的文件类型设置不同的
Content-Type
。
所以咱们这个 else
就长这个样子:
// ... 省略前后代码 ...
else {
// 应用 path 模块获取文件后缀名
const extName = path.extname(pathname);
if (extName === '.jpg') {
// 应用 fs 模块读取文件
fs.readFile(pathname, (err, data) => {res.setHeader('Content-Type', 'image/jpeg');
res.write(data);
res.end();})
}
}
而后咱们在同级目录下放一个图片试一下:
数据长久化
数据长久化的形式有好几种,个别都是存数据库,多数状况下也有存文件的。存数据库比拟麻烦,还须要创立和连贯数据库,咱们这里不好 demo
,咱们这里演示一个存文件的例子。个别POST
申请是用来存新数据的,咱们在后面的根底上再增加一个 POST /api/users
来新增一条数据,只须要在后面的 if (method === 'GET')
前面加一个 POST
的判断就行:
// ... 省略其余代码 ...
else if (method === 'POST') {
// 留神数据传过来可能有多个 chunk
// 咱们须要拼接这些 chunk
let postData = '';
req.on('data', chunk => {postData = postData + chunk;})
req.on('end', () => {
// 数据传完后往 db.txt 插入内容
fs.appendFile(path.join(__dirname, 'db.txt'), postData, () => {res.end(postData); // 数据写完后将数据再次返回
});
})
}
而后咱们测试一下这个API
:
再去看看文件外面写进去没有:
总结
到这里咱们就实现了一个具备基本功能的 web 服务器
,代码不简单,然而对于帮咱们了解Node web 服务器
的原理很有帮忙。然而上述代码还有个很大的问题就是:代码很丑 !所有代码都写在一堆,而且HTTP 动词
和路由匹配全副是应用 if
条件判断,如果有几百个 API
,再配合十来个动词,那代码几乎就是个劫难!所以咱们应该将 路由解决
,HTTP 动词
, 动态文件
, 数据长久化
这些性能全副抽离进去,让整个利用变得更优雅,更好扩大。这就是 Express
和Koa
这些框架存在的意义,下一篇文章咱们就去 Express
的源码看看他是怎么解决这个问题的,点个关注不迷路~
本文可运行代码示例曾经上传 GitHub,大家能够拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/Node.js/HttpServer
文章的最初,感激你破费贵重的工夫浏览本文,如果本文给了你一点点帮忙或者启发,请不要悭吝你的赞和 GitHub 小星星,你的反对是作者继续创作的能源。
作者博文 GitHub 我的项目地址:https://github.com/dennis-jiang/Front-End-Knowledges
我也搞了个公众号[进击的大前端],不打广告,不写水文,只发高质量原创,欢送关注~