HTTP入门(三):使用Nodo.js脚本实现简易服务器
- 本文通过简单的Node.js脚本模拟服务器请求与响应原理。
- 本文主要目的是对学习内容进行总结以及方便日后查阅。
- 本文所引用的图片和文字版权归原作者所有,侵权删。
- 如有错误请在下方评论区指出,欢迎积极讨论。
前言
- 硬件服务器:我们的电脑就是一个服务器。和普通的服务器的区别是:真正的服务器CPU可能有128G核,32、64、128G内存。没有GUI,没有显示器,用ssh远程登录,本质还是电脑
- 软件服务器:服务器上的软件。
服务器你已经有了,你使用的电脑就是服务器。但是你还没有提供 HTTP 服务的「程序」。
用脚本就可以提供 HTTP 服务,不管是 Bash 脚本还是 Node.js 脚本都可以。这篇文章先用 Node.js 脚本试试水。
接收请求
我们的脚本只需要一个文件就可以搞定:
-
新建一个安全的目录
cd ~/Desktop mkdir node-demo cd node-demo
touch server.js
-
编辑
server.js
,内容已上传到GitHub,所以用命令curl https://raw.githubusercontent.com/mtt3366/nodeserver/master/NodeServer.js > ./server.js
拷贝代码到
server.js
-
cat server.js
查看内容是否已经拷贝。
-
node server.js 8888
监听8888本地端口,这里端口参数不建议写0-1023,因为小于1024已经被规定使用,需要管理员权限才可以访问。 - 成功之后,这个 server 会保持运行,无法退出。
- 如果你想「中断」这个 server,按 Ctrl + C 即可(C 就是 Cancel 的意思),中断后你才能输入其他命令。
- 把这个 server 放在那里别动,新开一个 Bash 窗口,完成下面的测试
好了服务器完成。只不过
- 这个服务器目前只有一个功能,那就是打印出路径和查询字符串
- 还缺少一个重要的功能,那就是发出 HTTP 响应,目前我们先不发出响应
接下来要发起一个请求到这个服务器。这听起来有点怪异,「我向自己发起请求」,目前是的,因为我们的电脑既是客户端,又是服务器,还是会经历HTTP协议,还是会走一遍TCP/IP协议,所以用本机来学习服务器原理可行。接下来
- 在新的 Bash 窗口运行
curl http://localhost:8888/xxx
或者curl http://127.0.0.1:8888/xxx
。
你会马上发现 server 打印出了路径:
MTT说:得到 HTTP 路径
/xxx
MTT说:查询字符串为
MTT说:不含查询字符串的路径为
/xxx
这说明:
- 我们的 server 收到了我们用 curl 发出的请求
- 由于 server 迟迟没有发出响应,所以 curl 就一直等在那里,无法退出(用 Ctrl + C 中断这个傻 curl)
-
运行
curl "http://127.0.0.1:8888/xxx?name=ff"
打印结果:MTT说:得到 HTTP 路径 /xxx?name=ff MTT说:查询字符串为 ?name=ff MTT说:不含查询字符串的路径为 /xxx
这个服务器就一个功能,把路径和查询参数打印出来,不发出响应
发出响应
接下来我们让我们 server 发出响应,不在让客户端端一直等我们
- 编辑
server.js
- 在中间我标注的区域添加两行代码
response.write('Hi')
-
response.end()
如果没有这句话,客户端还会一直等 - 中断之前的 server,重新运行
node server 8888
-
curl http://127.0.0.1:8888/xxx
,结果如下: -
Hi%
这个 % 不是我们的内容,% 表示结尾。如果你看 % 不爽,就把 'Hi' 换成'Hi\n'
。 - 响应添加成功
- 使用
curl -s -v -- "http://localhost:8888/xxx"
可以查看完整的请求和响应
根据请求返回不同的响应
响应 /
与404
将中间的代码改为
if(path == "/" ){
response.write('Hi')
response.end()
} else{
response.statusCode = 404
response.end()
}
代码示例
不同的请求返回内容的截图
响应404
响应/
响应 /index.html
代码修改
响应示例
强调:后缀是废话。文件内容是有 HTTP 头中的 Content-Type
保证的
响应真正的网页
- 完整代码:
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]
if(!port){
console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
process.exit(1)
}
var server = http.createServer(function(request, response){
var parsedUrl = url.parse(request.url, true)
var path = request.url
var query = ''
if(path.indexOf('?') >= 0){ query = path.substring(path.indexOf('?')) }
var pathNoQuery = parsedUrl.pathname
var queryObject = parsedUrl.query
var method = request.method
/******** 从这里开始看,上面不要看 ************/
console.log('HTTP 路径为\n' + path)
if(path == '/style.js'){
response.setHeader('Content-Type', 'text/css; charset=utf-8')
response.write('body{background-color: #ddd;}h1{color: red;}')
response.end()
}else if(path == '/script.html'){
response.setHeader('Content-Type', 'text/javascript; charset=utf-8')
response.write('alert("这是JS执行的")')
response.end()
}else if(path == '/index.css'){
response.setHeader('Content-Type', 'text/html; charset=utf-8')
response.write('<!DOCTYPE>\n<html>' +
'<head><link rel="stylesheet" href="/style.js">' +
'</head><body>' +
'<h1>你好</h1>' +
'<script src="/script.html"></script>' +
'</body></html>')
response.end()
}else{
response.statusCode = 404
response.end()
}
/******** 代码结束,下面不要看 ************/
})
server.listen(port)
console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)
- 接下来
curl -s -v – "http://localhost:8888"
- 因为响应中
<link rel="stylesheet" href="/style.js">
和<script src="/script.html"></script>
服务器会接着继续发出/script
和/style
响应。 - 包括图片路径,也会发出响应。
- 模拟一下
/script
和/style
响应。
- 为了证实我们的想法,打开network查看请求与响应。发现确实有三个响应。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。