什么是 Web
服务器?
HTTP
请求获取到这个资源Web
服务器目前有很多开源的 Web
服务器:Nginx
、Apache(静态)
、Apache Tomcat(静态、动态)
、Node.js
在 Node
中,提供 web
服务器的资源返回给浏览器,主要是通过 http
模块。
我们先简单对它做一个使用:
jsconst http = require("http");
const HTTP_PORT = 9000;
const server = http.createServer((req, res) => {
res.end("Hello World");
});
server.listen(HTTP_PORT, () => {
console.log(`服务器在${HTTP_PORT}启动`);
});
此时我们在浏览器中输入 localhost:9000
,就会出现 Hello World
:
解释上面这段代码:
通过 http
模块的 createServer
方法创建了一个服务器对象,它的底层其实是直接使用 new Server
创建对象的。
那么当然,我们也可以自己来创建这个对象:
jsconst server = new http.Server((req, res) => {
res.end("Hello World");
});
server.listen(HTTP_PORT, () => {
console.log(`服务器在${HTTP_PORT}启动`);
});
创建 Server
时会传入一个回调函数,这个回调函数在被调用时会传入两个参数:
req
:request
请求对象,包含请求相关的信息;res
:response
响应对象,包含我们要发送给客户端的信息;Server
通过 listen
方法来开启服务器,并且在某一个主机的端口上监听网络请求
也就是当我们通过 ip:port
的方式发送到我们监听的 Web
服务器上时,我们就可以对其进行相关的处理;
listen
函数有三个参数:
端口 port
:可以不传,系统会默认分配端
主机 host
:通常可以传入 localhost
、ip地址127.0.0.1
、或者 ip地址0.0.0.0
,默认是 0.0.0.0
;
localhost
:本质上是一个域名,通常情况下会被解析成 127.0.0.1
;
127.0.0.1
:回环地址(Loop Back Address)
,表达的意思其实是我们主机自己发出去的包,直接被自己接收;
127.0.0.1
时,在同一个网段下的主机中,通过 ip地址
是不能访问的;0.0.0.0
:
IPV4
上所有的地址,再根据端口找到不同的应用程序;0.0.0.0
时,在同一个网段下的主机中,通过 ip
地址是可以访问的;回调函数:服务器启动成功时的回调函数;
在向服务器发送请求时,我们会携带很多信息,比如:
URL
,服务器需要根据不同的 URL
进行不同的处理;GET
、POST
请求传入的参数和处理的方式是不同的;headers
中也会携带一些信息,比如客户端信息、接收数据的格式、支持的编码格式等;这些信息,Node
会帮助我们封装到一个 request
的对象中,我们可以直接来处理这个 request
对象:
jsconst server = new http.Server((req, res) => {
// request 对象
console.log(req)
console.log(req.method)
console.log(req.headers)
res.end("Hello World");
});
客户端在发送请求时,会请求不同的数据,那么会传入不同的请求地址:
比如 http://localhost:9000/login
;
比如 http://localhost:9000/products
;
服务器端需要根据不同的请求地址,作出不同的响应:
jsconst server = new http.Server((req, res) => {
const url = req.url;
if (url === "/login") {
res.end("welcome Back~");
} else if (url === "/products") {
res.end("products");
} else {
res.end("error message");
}
});
如果用户发送的地址中还携带一些额外的参数,例如以下情况
http://localhost:9000/login?name=why&password=123
;
这个时候,url
的值是 /login?name=why&password=123
;
这个时候我们可以使用内置模块 url
处理
js const parseInfo = url.parse(req.url);
console.log(parseInfo)
此时的 parseInfo
为:
接下来我们就可以直接用 qs
或者 URLSearchParams
处理 query
拿到参数了
jsconst queryObj = new URLSearchParams(parseInfo.query);
console.log(queryObj.get("name"));
console.log(queryObj.get("password"));
在 request
对象的 header
中也包含很多有用的信息,客户端会默认传递过来一些信息:
content-type
是这次请求携带的数据的类型:
application/x-www-form-urlencoded
:表示数据被编码成以 '&'
分隔的键 -
值对,同时以 '='
分隔键和值application/json
:表示是一个 json
类型;text/plain
:表示是文本类型application/xml
:表示是 xml
类型;multipart/form-data
:表示是上传文件;content-length
:文件的大小长度keep-alive
:
http
是基于 TCP
协议的,但是通常在进行一次请求和响应结束后会立刻中断;http1.0
中,如果想要继续保持连接:
connection: keep-alive
;connection: keep-alive
;http1.1
中,所有连接默认是 connection: keep-alive
的;
Web
服务器会有不同的保持 keep-alive
的时间;Node
中默认是 5s
中;accept-encoding
:告知服务器,客户端支持的文件压缩格式,比如 js
文件可以使用 gzip
编码,对应 .gz
文件;accept
:告知服务器,客户端可接受文件的格式类型;user-agent
:客户端相关的信息;如果我们希望给客户端响应的结果数据,可以通过两种方式:
write方法
:这种方式是直接写出数据,但是并没有关闭流;end方法
:这种方式是写出最后的数据,并且写出后会关闭流;js// 响应数据的两个方式
res.write('Hello World)
res.write("Hello Response")
res.edn("message end")
如果我们没有调用 end
和 close
,客户端将会一直等待结果:
Http状态码(Http Status Code)
是用来表示 Http
响应状态的数字代码:
Http状态码
非常多,可以根据不同的情况,给客户端返回不同的状态码;MDN
响应码解析地址:https://developer.mozilla.org/zh-CN/docs/web/http/status常见HTTP状态码 | 状态描述 | 信息说明 |
---|---|---|
200 | OK | 客户端请求成功 |
201 | Created | POST请求,创建新的资源 |
301 | Moved Permanently | 请求资源的URL已经修改,响应中会给出新的URL |
400 | Bad Request | 客户端的错误,服务器无法或者不进行处理 |
401 | Unauthorized | 未授权的错误,必须携带请求的身份信息 |
403 | Forbidden | 客户端没有权限访问,被拒接 |
404 | Not Found | 服务器找不到请求的资源 |
500 | Internal Server Error | 服务器遇到了不知道如何处理的情况。 |
503 | Service Unavailable | 服务器不可用,可能处于维护或者重载状态,暂时无法访问 |
js// 1.
res.statusCode = 400
// 2.
res.writeHead(200)
返回头部信息,主要有两种方式:
res.setHeader
:一次写入一个头部信息;
res.writeHead
:同时写入 header
和 status
;
jsres.setHeader('Context-Type', 'application/json;charset=utf8')
res.writeHead(200, {
"Content-Type": "application/json;charset=utf8"
})
Header
设置 Content-Type
有什么作用呢?
其实对于后端,手动处理上传的文件是很复杂的,正常情况下我们都会借助于一些插件做处理, 下面仅做对于图片上传的一个简单的演示。
jsconst http = require("http");
const qs = require("querystring");
const fs = require("fs");
const HTTP_PORT = 9000;
// 1. 创建 sever 服务器
const server = new http.Server((req, res) => {
// 文件设置为二进制
req.setEncoding("binary");
// 获取 content-type 中的 boundary的值
let boundary = req.headers["content-type"]
.split("; ")[1]
.replace("boundary=", "");
const fileSize = req.headers["content-length"];
let curSize = 0;
let body = "";
req.on("data", (data) => {
curSize += data.length;
res.write(`文件上传进度:${(curSize / fileSize) * 100}%\n`);
body += data;
});
req.on("end", () => {
// 切割数据
const payload = qs.parse(body, "\r\n", ":");
// 获取最后的类型(image/png)
const fileType = payload["Content-Type"].substring(1);
// 获取要截取的长度
const fileTypePosition = body.indexOf(fileType) + fileType.length;
let binaryData = body.substring(fileTypePosition);
binaryData = binaryData.replace(/^\s\s*/, "");
const finalData = binaryData.substring(
0,
binaryData.indexOf("--" + boundary + "--")
);
fs.writeFile("./foo.png", finalData, "binary", (err) => {
console.log(err);
res.end("文件上传完成~");
});
});
});
// 2. 开启 server 服务器
server.listen(HTTP_PORT, () => {
console.log(`服务器在${HTTP_PORT}启动`);
});
使用 postman
测试,并查看图片能显示。
本文作者:叶继伟
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!