Open guyskk opened 3 years ago
理论上应该有3个参数,body参数、query参数和params参数,body参数和query参数比较好理解,params参数我个人认为是类似VueRouter的路径参数,比如/api/user/:id
那id就属于params参数。
我认为这3种参数应该同时解析出来提供给response函数,我看作者把query和params二选其一了。这种情况虽然在后端api中很少见但确实存在,在vue项目我们能经常见到query和params传参的情况,比如:/api/user/:id?name='小花'
。
为了解决application/x-www-form-urlencoded
参数的问题,不得不在rawResponse
函数种处理,为了使用方便因此封装了几个函数,便于直接使用。sendResponse
的回调函数可以同时返回query参数、params参数(需要传递mockUrl参数,值同url)和body参数。
使用案例:
import {
sendResponse,
resultSuccess,
resultError,
} from "./../utils";
// 假如真实请求是`/api/user/getgetUserInfo/1?name='小花'`,body参数是`age=18&sex=女`
export default [
{
url: "/api/user/getUserInfo/:id",
method: "post",
rawResponse: async (req, res) => {
await sendResponse(
req,
res,
({ url, body, query, params }) => {
console.log(url, body, query, params);
// 这里的body将打印{age: "18", sex: "女"};
// query将打印{name: "小花"}
// params将打印{id: "1"}
const item = data.list.find((item) => item.id === Number(params.id));
if (item) {
return resultSuccess(item);
}
return resultError("无此该用户");
},
"/api/user/getUserInfo/:id" // 想要获取params,这个参数必须传,值同url
);
},
},
]
声明:下面代码结合了源代码和 @guyskk 的代码
工具函数:
import url from "url";
import Mock from "mockjs";
import qs from "qs";
import { match } from "path-to-regexp";
/**
* 解析请求body参数
* @param {IncomingMessage} req 请求
* @returns body参数
*/
export function parseRequestBody(req) {
return new Promise((resolve) => {
const contentType = (req.headers["content-type"] || "").toLowerCase();
let body = "";
req.on("data", function (chunk) {
body += chunk;
});
req.on("end", function () {
let data = null;
if (contentType.includes("json")) {
try {
data = JSON.parse(body);
} catch (err) {
console.log(err);
}
} else if (contentType.includes("form")) {
try {
data = qs.parse(body);
} catch (err) {
console.log(err);
}
} else {
data = body;
}
resolve(data);
});
});
}
/**
* 解析请求的query参数和params参数(如果有params参数指的是path路径上的参数,比如:api/getItem/:id,id就是属于params参数)
* @param {IncomingMessage} req 请求
* @param {string} mockUrl mock数据的url
* @returns {query:Object,params:Object} query参数和params参数
*/
export function parseRequestQueryParams(req, mockUrl) {
let queryParams = {};
if (req.url) {
queryParams = url.parse(req.url, true);
}
const query = queryParams.query || {};
let params = {};
if (mockUrl) {
const urlMatch = match(mockUrl, {
decode: decodeURIComponent,
});
params = queryParams.pathname ? urlMatch(queryParams.pathname).params : {};
}
return { query, params };
}
/**
* 发送响应
* @param {IncomingMessage} req 请求
* @param {ServerResponse} res 响应
* @param {(opt: { [key: string]: string; body: Record<string,any>; query: Record<string,any>, headers: Record<string, any>; }) => any} callback 结果处理
* @param {string} [mockUrl=''] mock数据的url
*/
export async function sendResponse(req, res, callback, mockUrl = "") {
const body = await parseRequestBody(req);
const { query, params } = parseRequestQueryParams(req, mockUrl);
res.setHeader("Content-Type", "application/json");
res.statusCode = 200; // 无法从源码中获取statusCode,因此这里写死了200,因为99%情况下是200
const mockResponse =
typeof callback === "function"
? callback({ url: req.url, body, query, params, headers: req.headers })
: callback;
res.end(JSON.stringify(Mock.mock(mockResponse)));
}
目前请求体都当作JSON处理了,希望能支持
application/x-www-form-urlencoded
类型的参数。写了一个实现,合适的话我提个PR?