阅读原文
前言
从浏览器向服务器提交数据时,常见有表单提交,JSON 字符串提交和普通字符串提交,不同情况需要附带不同的请求头信息,告诉服务器客户端可以直接解析的数据格式,如果发送的数据为 json
字符串,后两种类型都可以成功发送到服务器,只是加上请求头信息服务器更容易判断该以什么格式返回数据。
querystring 模块解析请求体
在 get
请求中,我们可以通过 url
模块的 parse
方法来解析,如果是带有请求体的请求类型,如 post
、put
我们应该使用 querystring
模块的 parse
方法将请求体中的数据解析成对象,在这个方法中有三个参数。
- str:要解析的查询字符串;
- sep:查询字符串中键值对之间的分隔符,默认为
&
; - eq:查询字符串中的键与值的分隔符,默认为
=
。
// 文件:querystring-test.js
const querystring = require("querystring");
let str1 = "name=pandashen&age=27";
let str1 = "name*pandashen!&age*27";
let obj1 = querystring.parse(str1);
let obj2 = querystring.parse(str2, "!&", "*");
console.log(obj1); // { name: 'pandashen', age: '27'}
console.log(obj2); // { name: 'pandashen', age: '27'}
querystring
也是很常用的模块,就在这里多说几句关于原理相关的内容,模拟 querystring
模块常用方法 parse
的代码如下。
// 文件:my-querystring.js
exports.parse = (str, sep = "&", eq = "=") => {
// 存储解析出键值的对象
let query = {};
// 先将查询字符串切割成 [k=v, k=b] 的形式
let fields = str.split(sep);
// 循环将每一项切割成 k 和 v 并存入 queryObj 中
fields.forEach(field => {
let [key, value] = field.split(eq);
query[key] = value;
});
// 返回 query 对象
return query;
};
服务器的实现
向服务器发送请求的请求头为 Content-Type
,表单提交、json
和字符串作为请求体时,在 Content-Type
中对应的值分别为 application/x-www-form-urlencoded
、application/json
和 text/plain
。
其中 text/plain
为 Ajax 的默认提交方式,我们在服务器中针对上面这几种类型的请求头和 get
请求做处理,将发来的数据再次返回客户端。
// 文件:server.js
const http = require("http");
const url = require("url");
const querystring = require("querystring");
const server = http.createServer((req, res) => {
// 获取 get 请求参数
let { query } = url.parse(req.url, true);
// 获取数据类型请求头
let type = req.headers["content-type"];
// 接收数据
let buffers = [];
res.on("data", data => buffers.push(data));
res.on("end", () => {
// 合并数据并设置默认响应头和返回数据
let data = Buffer.concat(buffers).toString();
let contentType = "application/json";
// 判断是否为 get 请求,是则直接返回解析后的数据,不是则判断请求类型
if (req.method.toLowerCase() === "get") {
data = JSON.stringify(query);
} else {
// 判断请求数据类型并做相应处理
if (type === "application/x-www-form-urlencoded") {
data = JSON.stringify(querystring.parse(str));
} else if (type === "application/json") {
data = JSON.stringify(JSON.parse(str));
} else {
contentType = "text/plain";
}
}
// 设置响应头并返回数据
res.setHeader("Content-Type", contentType);
res.end(data);
});
});
server.listen(3000, () => {
console.log("server start 3000");
}
当请求类型为 get
,将 URL 的查询字符串通过 url
模块解析后再处理成字符串返回客户端。
当请求类型为 post
,设置默认响应头为 application/json
,如果是表单提交,请求体中的内容为查询字符串格式,使用 querystring
解析后再使用 JSON.stringify
处理成字符串返回,如果是 json
,则使用 JSON.parse
解析,并使用 JSON.stringify
处理成字符串返回,如果是默认值 text/plain
,则设置响应头的值为 text/plain
并将读取的结果直接返回。
使用客户端进行测试
在这里我们为了方便就不用浏览器访问了,因为上面的服务器代码比较简单,只处理了数据,并没有处理静态文件请求,所以我们通过 NodeJS 来实现客户端。
1、get 请求
// 文件:get.js
const http = require("http");
let config = {
host: "localhost",
port: 3000,
path: "/?name=pandashen&age=27"
};
// 发送 get 请求
http.get(config, res => {
// 接收服务器返回的数据
let buffers = [];
res.on("data", data => buffers.push(data));
res.on("end", () => {
let data = Buffer.concat(buffers).toString();
console.log(data);
});
});
启动服务器 server.js
,通过命令行执行 node get.js
查看命令窗口中输出的结果。
2、post 请求表单提交
// 文件:post-from.js
const http = require("http");
let config = {
host: "localhost",
port: 3000,
method: "post"
headers: {
"Content-type": "application/x-www-form-urlencoded"
}
};
http.request(config, res => {
// 接收服务器返回的数据
let buffers = [];
res.on("data", data => buffers.push(data));
res.on("end", () => {
let data = Buffer.concat(buffers).toString();
console.log(data);
});
}).end("name=pandashen&age=27");
启动服务器 server.js
,通过命令行执行 node post-form.js
查看命令窗口中输出的结果。
3、post 请求 json 字符串数据
// 文件:post-json.js
const http = require("http");
let config = {
host: "localhost",
port: 3000,
method: "post",
headers: {
"Content-Type": "application/json"
}
};
http.request(config, res => {
// 接收服务器返回的数据
let buffers = [];
res.on("data", data => buffers.push(data));
res.on("end", () => {
let data = Buffer.concat(buffers).toString();
console.log(data);
});
}).end("{ name: pandashen, age: 27 }");
启动服务器 server.js
,通过命令行执行 node post-json.js
查看命令窗口中输出的结果。
4、post 请求普通字符串数据
// 文件:post-string.js
const http = require("http");
let config = {
host: "localhost",
port: 3000,
method: "post",
headers: {
"Content-Type": "text/plain"
}
};
http.request(config, res => {
// 接收服务器返回的数据
let buffers = [];
res.on("data", data => buffers.push(data));
res.on("end", () => {
let data = Buffer.concat(buffers).toString();
console.log(data);
});
}).end("pandashen27");
启动服务器 server.js
,通过命令行执行 node post-string.js
查看命令窗口中输出的结果。
总结
通过本篇的内容可以了解 HTTP 在数据传输中的类型,即请求头类型,服务端通过请求头类型可以返回客户端可以直接解析的数据,上面的几种类型只是向服务器提交数据的最常见类型,涵盖表单提交和 Ajax 等,在上传文件时还存在二进制传输等等。