从零开始用nodejs写一个简单的静态服务器
nodejs搭建服务器第一步
const http = require("http")
const PORT = 8000
const server = http.createServer((req, res) => {
res.end()
})
server.listen(PORT)
很简单,使用 http 这个模块中的createServer方法,该方法接收一个函数,函数的参数有两个,第一个是 req(request,代表请求的相关信息),第二个是res(response,代表响应的相关信息)。在函数里我们什么都不做,直接使用res.end()结束响应。最后使用server.listen(PORT)表示监听8000端口
处理请求和响应
上一步已经创建了一个简单的服务器,但是没有做任何处理直接结束了,这次我们加一些逻辑
const http = require("http")
const PORT = 8000
const server = http.createServer((req, res) => {
if (req.method === "GET") {
res.setHeader("Content-Type", "text/html;charset=utf-8")
res.end("<h1>Hello NOdejs</h1>")
}
})
server.listen(PORT)
这里加的逻辑就是如果 http 请求是 GET 请求,那么就返回 Hello Nodejs。
现在在浏览器中输入localhost:8000就可以看到 Hello Nodejs 了

其实就是浏览器发送了一个 GET 请求给我们写的服务器,我们的服务器接收到了该请求,并确认该请求是 GET 请求后,就返回了一个 html 给浏览器
加入读写文件的支持
上一步已经能从服务器返回数据了,但是我要做的是静态服务器啊,返回的是写好的 html 或者 js文件,直接这样在res.end()里写好像不太现实,兵来将挡水来土掩,这时候用 nodejs 操作文件就可以了。
const http = require("http")
const fs = require("fs")
const url = require("url")
const path = require("path")
const PORT = 8000
// 这次为了清楚,我们把函数单独拿出来写
const serverHandle = (req, res) => {
// pathObj 是解析 url 得到的对象
const pathObj = url.parse(req.url, true)
console.log(pathObj)
// __dirname 指的是当前文件夹在文件系统中的绝对路径,pathname是要打开的文件的相对路径
// 通过 path.join 将两者拼接起来,就是要打开的文件的绝对路径
const filePath = path.join(__dirname, pathObj.pathname)
fs.readFile(filePath, "binary", (err, file) => {
if (err) {
res.writeHead(404, "not found")
res.end("<h1>404 NOT FOUND</h1>")
} else {
res.write(file, "binary")
res.end()
}
})
}
http.createServer(serverHandle).listen(PORT)
console.log(`正在监听${PORT}端口`)

我们的目录结构是这样的
我们在浏览器中输入 http://localhost:8000/static/index.html?a=1&b=1,就可以正确的打开 index.html文件了
分析一下上面的代码
-

这是pathObj,为什么前面那么多null呢,因为req.url 不会获取完整的 url,只会获取客户端发送过来的,即 chrome 中 network 的那部分

-
url.parse(req.url, true)表示的是将该 url 解析成一个对象。其中第二个参数可省略,省略的话默认是false。设置为true将自动将查询参数转换成对象,什么意思呢? 解析后的对象中有个query的属性: false的话,query对应的值 => 'a=1&b=1' true的话,query对应的值 => { a: '1', b: '1' } 方便后面的调用(url.parse(request.url, true).query.a) -
fs.readFile函数第一个参数传的是文件的路径,第二个参数是编码方式,这里采用二进制方式(和后面的res.write配合,下一条会说),第三个参数是回调函数 -
res.write(file, "binary")因为这里用了二进制返回数据,所以之前的fs.readFile就要用二进制的编码方式,原因参见官方文档
第一个chunk参数就是我们的文件,我们的文件显然不是String类型,所以
fs.readFile和res.write都要采用二进制的编码方式
一点微小的改进
const http = require("http")
const fs = require("fs")
const url = require("url")
const path = require("path")
const PORT = 8000
const serverHandle = (req, res) => {
// 改了下面的两行!!!
const url = new URL(req.url)
const filePath = path.join(__dirname, url.pathname)
fs.readFile(filePath, "binary", (err, file) => {
if (err) {
res.writeHead(404, "not found")
res.end("<h1>404 NOT FOUND</h1>")
} else {
res.write(file, "binary")
res.end()
}
})
}
http.createServer(serverHandle).listen(PORT)
console.log(`正在监听${PORT}端口`)
之所以要这样改,参见官方文档

之前用的接口即将过时,所以采用新的,新的和旧的的区别见下图
