Express 恳求 req 和呼应 res 目标定义:
var req = Object.create(http.IncomingMessage.prototype)
var res = Object.create(http.ServerResponse.prototype)
下面是特点承继联系:
原型 | 承继来历类 |
---|---|
http.IncomingMessage.prototype | Stream.Reabable |
http.ServerResponse.prototype | IncomingMessage |
IncomingMessage
class IncomingMessage extends stream.Readable {
constructor(socket: Socket);
aborted: boolean;
httpVersion: string;
httpVersionMajor: number;
httpVersionMinor: number;
complete: boolean;
connection: Socket;
socket: Socket;
headers: IncomingHttpHeaders;
rawHeaders: string[];
trailers: NodeJS.Dict<string>;
rawTrailers: string[];
setTimeout(msecs: number, callback?: () => void): this;
method?: string | undefined;
url?: string | undefined;
statusCode?: number | undefined;
statusMessage?: string | undefined;
destroy(error?: Error): this;
}
ServerResponse
class ServerResponse<Request extends IncomingMessage = IncomingMessage> extends OutgoingMessage<Request> {
statusCode: number;
statusMessage: string;
constructor(req: Request);
assignSocket(socket: Socket): void;
detachSocket(socket: Socket): void;
writeContinue(callback?: () => void): void;
writeEarlyHints(hints: Record<string, string | string[]>, callback?: () => void): void;
writeHead(
statusCode: number,
statusMessage?: string,
headers?: OutgoingHttpHeaders | OutgoingHttpHeader[],
): this;
writeHead(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[]): this;
writeProcessing(): void;
}
接下来的任务仍是很简单,看看 express 是怎么处理恳求 req 目标上的特点和办法。
恳求目标 req
在 req 目标上扩展办法
特点和办法名 | 阐明 |
---|---|
get()/header() |
回来指定的 HTTP 恳求头字段(不区别大小写的匹配)。 |
accepts() |
根据恳求的 HTTP 标字段查看指定的内容类型 是否可承受。 |
acceptsEncodings() |
回来指定编码的第一个承受编码。 |
acceptsCharsets() |
回来指定字符集的第一个承受的字符集。 |
acceptsLanguages() |
回来指定言语的第一个承受言语。 |
range() |
Range 标头解析器。 |
param() |
回来 req 目标中 params
|
is() |
假如传入恳求的 内容类型 HTTP 头字段,则回来匹配的内容类型 匹配参数指定的 MIME 类型。 |
运用 defineGetter 函数扩展特点:
function defineGetter(obj, name, getter) {
Object.defineProperty(obj, name, {
configurable: true,
enumerable: true,
get: getter
});
}
特点 | 阐明 |
---|---|
protocol |
协议 |
secure |
是否安全 |
ip |
恳求的 ip 地址 |
ips |
恳求头中的 ip 地址数组 |
subdomains |
恳求中的子域名 |
path |
包括恳求 URL 的途径部分。 |
hostname |
主机名 |
fresh |
是否为最新的 |
stale |
是否为过时的 |
xhr |
恳求中是否包 xmlHTTPRequest 字符串 |
这是特点仍是跟 HTTP 通讯,前后端通讯 xhr,如:完好的途径 path/protocol/secure/subdomains, ip 相关,服务器相关 fresh/stable。
呼应目标
在 res 目标上扩展办法:
特点和办法名 | 阐明 |
---|---|
status() |
设置呼应状况码。 |
links() |
用给定的 links 设置头字段 |
send() |
发送 HTTP 呼应。 |
json() |
发送 JSON 呼应。 |
jsonp() |
发送 JSONP 呼应。 |
sendStatus() |
发送状况码 |
sendFile() |
在给定的途径 处传输文件。 |
sendfile() |
在给定的 .设置呼应 HTTP 头字段 基于文件名的扩展名。 |
download() |
下载文件 |
type() |
将 HTTP 标头设置为由指定的。 |
format() |
格式化恳求目标的上内容 |
attachment() |
在呼应头中添加额定的内容 |
append() |
将数据最加到尾部 |
set()/header() |
设置 http 头信息 |
get() |
获取指定 http 头数据 |
clearCookie() |
清除 cookie 内容 |
cookie() |
设置 cookie |
location() |
将呼应 HTTP 标头设置为指定的参数。 |
redirect() |
重定向地址 |
vary() |
运用 vary 办法添加字段到恳求头 |
render() |
烘托模板中 html |
设置状况码
res.status(203)
console.log(res.statusCode)
res.send("get v1: hello world!")
怎么来快速测验这些特点和办法呢?
- 准备好接口, 了解 restful api 或者其他范式的形式接口
- 准备写接口时的东西。curl(了解命令行)、东西(类似于:postman 等等)
- 将东西接口与 express 的接口对应起来进行调试测验,验证特点。本项目运用
下面给出一些示例代码
目录结构
.
├── __tests__
├── babel.config.js
├── index.js
├── index.md
├── jest.config.js
├── node_modules
├── package.json
├── pnpm-lock.yaml
├── public
└── views
安装依靠
- views 中的 home.ejs 需求 ejs, 内容如下:
<html>
<head>
<title>Home 页面</title>
</head>
<body>
<h2>欢迎来到 Home 页面</h2>
</body>
</html>
安装其他的依靠包:
pnpm install ejs babel-jest dirname-filename-esm jest nodemon supertest @babel/preset-react @babel/preset-env @babel/plugin-syntax-jsx @babel/core
看看 package.json 项目装备
{
"name": "debugger-source-code",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "nodemon index.js",
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.21.0",
"@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"babel-jest": "^29.4.3",
"dirname-filename-esm": "^1.1.1",
"ejs": "^3.1.8",
"express": "^4.18.2",
"jest": "^29.4.3",
"nodemon": "^2.0.20",
"supertest": "^6.3.3"
}
}
看看 babel 装备
export default {
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-react",
],
};
看看 eslint 装备
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": "eslint:recommended",
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
}
}
看看 jest 装备
export default {
transform: {
'\\.[jt]s?$': 'babel-jest'
},
};
express 主要服务 index.js
import express from "express";
import path from "path";
import { dirname } from "dirname-filename-esm";
const __dirname = dirname(import.meta);
const app = express();
app.set("view engine", "ejs");
app.use(express.static(path.join(__dirname, "public")));
app.get("/req", (req, res, next) => {
console.log(req.protocol); // http 协议
console.log(req.secure); //fals
console.log(req.ip); //::1
console.log(req.ips); // []
console.log(req.subdomains); // []
console.log(req.path); // /favicon.ico
console.log(req.host); // localhost 已经被抛弃
console.log(req.hostname); // localhost
console.log(req.fresh); // false
console.log(req.stale); // true
console.log(req.xhr); //false
//------------- get ------------- //
let a1 = req.get("set-cookie");
console.log("set-cookie", a1); // undefined
//------------- header ------------- //
let a2 = req.header("set-cookie");
console.log("set-cookie", a2); // undefined
//------------- accepts ------------- //
let b1 = req.accepts();
console.log("accepts", b1);
// accepts [
// 'image/avif',
// 'image/webp',
// 'image/apng',
// 'image/svg+xml',
// 'image/*',
// '*/*'
// ]
//------------- acceptsEncodings ------------- //
let b2 = req.acceptsEncodings();
console.log("acceptsEncodings", b2); // [ 'gzip', 'deflate', 'br', 'identity' ]
//------------- acceptsLanguages ------------- //
let c1 = req.acceptsLanguages();
console.log("acceptsLanguages", c1); // [ 'zh-CN', 'zh' ]
//------------- range ------------- //
let range = req.range(10, {});
console.log("range", range); // undefined
//------------- param ------------- //
let param = req.param();
console.log("param", param); // undefined
res.send("hello world!");
});
app.get("/res/status", (req, res, next) => {
res.status(203);
console.log(res.statusCode);
res.send("get v1: hello world! and status code: 203 === " + res.statusCode);
});
app.get("/res/statusCode", (req, res, next) => {
res.send("get v1: hello world! and status code:" + res.statusCode);
});
app.get("/res/links", (req, res, next) => {
res.links({
a: "http://localhost:3232",
});
res.send("links set"); // header Link filed
});
app.get("/res/send", (req, res, next) => {
res.send("links set"); //type: string
});
app.get("/res/send/object", (req, res, next) => {
res.send({ msg: "123" }); // type object json
});
app.get("/res/send/json", (req, res, next) => {
res.json(JSON.stringify({ msg: "json" })); // type object json
});
app.get("/res/send/jsonp", (req, res, next) => {
let fn = req.query.fn;
let data = JSON.stringify({
data: "mydata",
});
res.end(fn + data); // type object json
});
app.get("/res/send/sendStatus", (req, res, next) => {
res.sendStatus(404);
});
app.get("/res/send/sendFile", (req, res, next) => {
res.sendFile(path.join(__dirname, "jest.config.js"));
});
app.get("/res/send/download", (req, res, next) => {
res.download(path.join(__dirname, "jest.config.js"));
});
app.get("/res/send/type", (req, res, next) => {
res.type(".html").send("<div>123</div>");
// image/png
console.log(res.get("Content-type"));
});
app.get("/res/send/format", (req, res, next) => {
res.format({
"text/html": function () {
res.send("<div>This is html</div>");
},
"text/pain": function () {
res.send("this is html text");
},
"application/json": function () {
res.send({ message: "This is html json" });
},
default: function () {
res.status(406).send("Not Acceptable");
},
});
});
app.get("/res/send/attachment", (req, res, next) => {
res.attachment("index.md");
console.log(req.get("Content-Disposition"));
res.send("attachment");
// attachment; filename="index.md"
});
app.get("/res/send/append", (req, res, next) => {
res.append("Warning", "201 Warning");
console.log(res.get("Warning")); // Warning 201 Warning
res.send("append");
});
app.get("/res/send/set", (req, res, next) => {
res.set("set8", "set8888"); //呼应 header 中
res.send("set");
});
app.get("/res/send/header", (req, res, next) => {
res.header("set9", "set9999"); //呼应 header 中
res.send("set9");
});
app.get("/res/send/get", (req, res, next) => {
res.set({
"Content-Type": "text/plain",
"Content-Length": "123",
ETag: "12345",
});
let ct = res.get("Content-Type"); //呼应 header 中
res.send("[get => ]" + ct);
});
app.get("/res/send/cookie", (req, res, next) => {
res.cookie("abc", "dd"); //呼应 header 中
res.send("cookie: abcdd");
});
app.get("/res/send/clearCookie", (req, res, next) => {
res.cookie("abc", "dd");
res.cookie("def", "xj");
res.clearCookie("abc");
res.send("cookie: abcdd");
});
app.get("/res/send/location", (req, res, next) => {
res.location("http://demo.com");
console.log(res.get("location")); // http://demo.com
res.send(res.get("location"));
});
app.get("/res/send/redirect", (req, res, next) => {
res.redirect("/res/send/redirect-new");
});
app.get("/res/send/redirect-new", (req, res, next) => {
res.send("this is redirect-new");
});
app.get("/res/send/vary", (req, res, next) => {
res.vary("User-Agent").send("Field added to the Vary response header");
});
app.get("/res/send/render", (req, res, next) => {
res.render('home')
});
app.listen(3232, () => {
console.log("listening on http://localhost:3232");
});
小结
本文主要介绍了 express 的恳求和呼应目标,以及集成目标,各种用处,并运用一个实例,来进行阐明。在测验实际接口时候,运用了 nodemon 来自动重启服务,运用 apifox 来保存接口重复发送测验接口。