使用 Node.js 创建 http 服务器需要使用内置的 http
模块
创建 web server
Node.js 是运行在服务器环境的 JavaScript,这里的服务器更多指的是物理概念的服务器,也就是主机。
使用 Node.js 创建 HTTP 服务器指的是软件概念的服务器,也就是 web server,类似于 nginx、apache
const http = require('http');
const server = http.createServer((req, res) => {
res.write('Hello\n');
res.end();
})
server.listen(9527, () => {
console.log('Web Server started at port 9527');
})
上面 10 行代码创建了一个最简单的 HTTP 服务器,服务器监听端口号 9527,接收到请求后返回字符串 Hello\n
,可以使用浏览器或者 curl 工具测试
req
req 代表本次 http request,是一个可读流,常用有几个属性
- url:本地请求的地址
- method:HTTP 请求的方法(GET、POST、DELETE、PUT 等)
-
res
res 代表本次 http response,是一个可写流,常用的属性方法有
writeHead(statusCode,[, StatusMessage[, headers]])
:发送响应首部,包含状态码、状态信息、响应头write(chunk)
:向响应主体中写入字符串或者 bufferend(chunk)
:向服务器发出信号,可以携带最后发送的数据,表明已发送所有响应头和主体,每个响应都需要调用一次getHeader(name)
:返回指定 name 的 headergetHeaders()
:返回包含了所有 header 信息的对象setHeader(name, value)
:设置响应头,和 writeHead() 合并,有冲突时优先使用 writeHead()statusCode
:设置响应 HTTP status ```javascript const http = require(‘http’);
const server = http.createServer((req, res) => { const { url, method, headers } = req;
res.setHeader(‘content-type’, ‘text/txt;charset=utf-8’);
res.write(请求 URL: ${url}\n
);
res.write(请求方法: ${method}\n
);
res.write(请求 headers:${JSON.stringify(headers, null, ' ')}
);
res.end(‘\n’); });
server.listen(3000, () => { console.log(‘Web Server started at port 3000’); });
<a name="Slg4c"></a>
# 返回文件内容
上面例子和真实的 web server 还有很大差距,下面例子展示了一个最简单的返回文件内容的静态资源服务器
> demo 中使用了 mime-types 包来根据文件名称获取文件的 Content-Type,运行 demo 需要在代码目录安装 mime-types
|-demo |-public |-index.html |-pic.png |-my.txt |-movie.mp4 |-server.js
```javascript
const http = require('http')
const path = require('path')
const fs = require('fs')
const mime = require('mime-types')
// 静态资源根目录,可以设定为本地的任意有权限目录,放入 a.jpg 测试
const ROOT_DIRECTORY = '/public'
const server = http.createServer((req, res) => {
const { url } = req
const filePath = path.join(__dirname, ROOT_DIRECTORY, url)
fs.readFile(filePath, (err, chunk) => {
if (err) {
res.writeHead(404, {
'content-type': 'text/html;charset=utf-8',
})
res.end('文件不存在!')
} else {
res.writeHead(200, {
'content-type': mime.contentType(path.extname(url)),
})
res.end(chunk)
}
})
})
server.listen(3000, () => {
console.log('Web Server started at port 3000')
})
我们可以在浏览器打开 http://localhost:3000/index.html
,其他资源的路径与其在public
文件下的路径一致。
读取电影文件
理论上读取电影文件可以使用和上面一样的代码,但实际执行会发现电影文件在完全读取到内存后才返回给浏览器,这样返回内容耗时极长,而且电影文件过大的话程序也没有办法处理,HTTP 协议是支持分段传输的(Transfer-Encoding: chunked)。
既然 res 是可写流,可以简单使用 stream 来做到边读取内容边返回给浏览器,而不是一次读取完成后返回
const http = require('http');
const path = require('path');
const fs = require('fs');
const mime = require('mime-types');
// 静态资源根目录
const ROOT_DIRECTORY = '/public';
const server = http.createServer((req, res) => {
const { url } = req;
const filePath = path.join(__dirname, ROOT_DIRECTORY, url);
fs.access(filePath, fs.constants.R_OK, err => {
if (err) {
res.writeHead(404, {
'content-type': 'text/html;charset=utf-8',
});
res.end('文件不存在!');
} else {
res.writeHead(200, {
'content-type': mime.contentType(path.extname(url)),
});
fs.createReadStream(filePath).pipe(res);
}
});
});
server.listen(3000, () => {
console.log('Web Server started at port 3000');
});
Node.js 官网一次 HTTP 传输解析 对 HTTP Server 做了入门讲解,顺便介绍了一些 HTTP 协议的相关知识,值得阅读