Server Middleware
服务端中间件在每次入站 RPC 前后包一层。思路与 客户端中间件 相同,区别在上下文:这里你可以读取入站 metadata、修改响应、附加 trailing metadata,或把抛出的错误转成 status。
洋葱模型
gRPCity 服务端同样使用 Koa 风格的洋葱模型中间件:每个函数自己决定何时调 next(),next() 之前与之后的代码把下层逻辑包在中间。
按 a → b → c 顺序注册三个中间件,调用轨迹如下:
enter a
enter b
enter c
rpc-method()
exit c
exit b
exit a用法
gRPCity server 提供了server.use()的方法用于添加中间件。
当前版本只有 async unary 和 async stream 的方法支持中间件,stream 和 callback 暂不支持。
使用方法如下:
const server = await loader.initServer()
// 逐个添加
server.use(f1)
server.use(f2)
server.use(f3)
// 传入多个参数添加
server.use(f1, f2, f3)
// 使用数组添加
server.use([f1, f2, f3])添加中间件的使用位置在initServer()之后,在listen()之前。
上下文
const middleware = async (ctx, next) => {
console.log(ctx)
await next()
console.log(ctx)
}第一个打印的上下文,可以看到包含了 path、method、request、metadata、peer,这些都是进行服务器处理之前获取的,可以对其进行修改。
其中method包含了调用的类型和请求的metadata和options参数。
Terminal
{
path: '/helloworld.Greeter/SayGreet',
method: {
requestStream: false,
responseStream: false
},
request: { name: 'greeter' },
metadata: Metadata {
internalRepr: Map(3) {
'x-client-hostname' => [Array],
'x-service-path' => [Array],
'user-agent' => [Array]
},
options: {}
},
peer: '127.0.0.1:64929'
}第二个打印上下文,额外response,是执行后添加的,可以修改,最终响应的是修改好的结果。
Terminal
{
path: '/helloworld.Greeter/SayGreet',
method: {
requestStream: false,
responseStream: false
},
request: { name: 'greeter' },
metadata: Metadata {
internalRepr: Map(3) {
'x-client-hostname' => [Array],
'x-service-path' => [Array],
'user-agent' => [Array]
},
options: {}
},
peer: '127.0.0.1:64929',
response: { message: 'hello greeter by Greeter', count: 1 }
}例子
log.js
const log = async (ctx, next) => {
const startTime = Date.now()
await next()
const responseTimeMs = Date.now() - startTime
console.log({
path: ctx.path,
peer: ctx.peer,
request: ctx.request,
responseTimeMs
})
}
export default log添加中间件
server.js
import log from './log.js'
// other...
server.use(log)至此,我们完成了服务端中间件的编写与使用。
Last updated on