跳到主要内容

自定义 HTTP 响应

注意

本节的内容仅适用于 HttpServer

使用 TSRPC,虽然有配套的客户端,不需要去考虑构建 HTTP 请求的细节。 但是有些时候,你可能会想要后端支持一些特定的普通请求。 例如服务器信息页,静态文件服务,或者一些简单的控制类 GET 接口之类。

通过 Flow,你也可以完成这些操作,甚至将 TSRPC 嫁接到其它框架上。

实现

server.flows.preRecvDataFlow 的节点函数中,有一个参数字段为 conn, 它即是实际传输协议的 Connection。 由于 TSRPC 实现为跨传输协议的,所以你直接取到的 connBaseConnection 类型。

如果你创建的是 HttpServer,则对应的 conn 实际是 HttpConnection。 此时,通过 conn.httpReqconn.httpEnd 你可以获取到 NodeJS 原生 http 模块的 reqres 对象,然后就可以自由进行操作了。

如果你要返回自己的响应,则可以通过 conn.httpRes 去实现。 但记得在那之后 return undefined 来中断 Flow 和后续流程, 这样就不会进入到后面的二进制解码、API 解析等环节。

例如:

// Custom HTTP Reponse
server.flows.preRecvDataFlow.push(v => {
let conn = v.conn as HttpConnection;

if (conn.httpReq.method === 'GET') {
conn.httpRes.end('Hello World');
return undefined;
}

return v;
})

然后在浏览器里直接打开后端服务地址 http://localhost:3000,可以看到我们的自定义响应:

进一步的,你可以实现一个简单的文件服务:

// Custom HTTP Reponse
server.flows.preRecvDataFlow.push(async v => {
let conn = v.conn as HttpConnection;

if (conn.httpReq.method === 'GET') {
// 静态文件服务
if (conn.httpReq.url) {
// 检测文件是否存在
let resFilePath = path.join('res', conn.httpReq.url)
let isExisted = await fs.access(resFilePath).then(() => true).catch(() => false);
if (isExisted) {
// 返回文件内容
let content = await fs.readFile(resFilePath);
conn.httpRes.end(content);
return undefined;
}
}


// 默认 GET 响应
conn.httpRes.end('Hello World');
return undefined;
}

return v;
})

完整例子

参见:https://github.com/k8w/tsrpc-examples/tree/main/examples/custom-http-res

提示

TSRPC 的 API 和 Message 通讯都是通过 POST 方法,所以确保你不会影响到它们。