Express框架req res对象使用详解

JavaScript/前端
266
0
0
2023-09-07
目录
  • 正文
  • IncomingMessage
  • ServerResponse
  • 请求对象 req
  • 响应对象
  • 设置状态码
  • 如何来快速测试这些属性和方法呢?
  • 下面给出一些示例代码
  • 目录结构
  • 安装依赖
  • 小结

正文

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()
console.log(res.statusCode)
res.send("get v: 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>
    <h>欢迎来到 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": ".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": "^.21.0",
    "@babel/plugin-syntax-jsx": "^.18.6",
    "@babel/preset-env": "^.20.2",
    "@babel/preset-react": "^.18.6",
    "babel-jest": "^.4.3",
    "dirname-filename-esm": "^.1.1",
    "ejs": "^.1.8",
    "express": "^.18.2",
    "jest": "^.4.3",
    "nodemon": "^.0.20",
    "supertest": "^.3.3"
  }
}

看看 babel 配置

export default {
  presets: [
    ["@babel/preset-env", { targets: { node: "current" } }],
    "@babel/preset-react",
  ],
};

看看 eslint 配置

module.exports = {
    "env": {
        "browser": true,
        "es": 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); //::
  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 a = req.get("set-cookie");
  console.log("set-cookie", a); // undefined
  //------------- header ------------- //
  let a = req.header("set-cookie");
  console.log("set-cookie", a); // undefined
  //------------- accepts ------------- //
  let b = req.accepts();
  console.log("accepts", b);
  //   accepts [
  //   'image/avif',
  //   'image/webp',
  //   'image/apng',
  //   'image/svg+xml',
  //   'image/*',
  //   '*/*'
  // ]
  //------------- acceptsEncodings ------------- //
  let b = req.acceptsEncodings();
  console.log("acceptsEncodings", b); //  [ 'gzip', 'deflate', 'br', 'identity' ]
  //------------- acceptsLanguages ------------- //
  let c = req.acceptsLanguages();
  console.log("acceptsLanguages", c); // [ 'zh-CN', 'zh' ]
  //------------- range ------------- //
  let range = req.range(, {});
  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();
  console.log(res.statusCode);
  res.send("get v: hello world! and status code: 203 === " + res.statusCode);
});
app.get("/res/statusCode", (req, res, next) => {
  res.send("get v: hello world! and status code:" + res.statusCode);
});
app.get("/res/links", (req, res, next) => {
  res.links({
    a: "http://localhost:",
  });
  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: "" }); // 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();
});
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></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().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", " Warning");
  console.log(res.get("Warning")); // Warning Warning
  res.send("append");
});
app.get("/res/send/set", (req, res, next) => {
  res.set("set", "set8888"); //响应 header 中
  res.send("set");
});
app.get("/res/send/header", (req, res, next) => {
  res.header("set", "set9999"); //响应 header 中
  res.send("set");
});
app.get("/res/send/get", (req, res, next) => {
  res.set({
    "Content-Type": "text/plain",
    "Content-Length": "",
    ETag: "",
  });
  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(, () => {
  console.log("listening on http://localhost:");
});

小结

本文主要介绍了 express 的请求和响应对象,以及集成对象,各种用途,并使用一个实例,来进行说明。在测试实际接口时候,使用了 nodemon 来自动重启服务,使用 apifox 来保存接口重复发送测试接口。