Skip to content

中间件与代理 ​

cormi dev、cormi start 运行一个 HTTP 服务(@cordisjs/plugin-server)。一个请求依次经过:

  1. 文件与转发:开发服务器提供的模块(dev)、构建产物中的静态资源(start)、mock、代理。它们直接回答,不经过下面的中间件;
  2. 应用的中间件(ctx.middleware),按 order 从外到内;
  3. 路由:接口(server/api)、loader 端点、插件注册的路由;
  4. 页面:GET 请求的回退,开启 SSR 时在服务端渲染。

所以中间件包裹的是应用自己的请求——接口、loader 与页面——会话、鉴权、限流只作用于它们,而不会为每个脚本、图片读一次会话。

中间件 ​

中间件基于 fetch:收到 Request,返回 Response。next() 是之后的一切——内层的中间件、路由与页面;中间件可以修改它的响应,也可以不调用它而直接返回:

ts
import type { Context } from '@cormijs/cormi'

export const inject = ['middleware']

export function apply(ctx: Context) {
  ctx.middleware.use(async (request, { state }, next) => {
    const start = performance.now()
    const response = await next()
    response.headers.set('server-timing', `app;dur=${(performance.now() - start).toFixed(1)}`)
    return response
  }, { path: '/api' })
}
选项默认值说明
order0小的在外层:先看到请求、后看到响应
path/只处理这个路径之下的请求

ctx.middleware.use() 是调用方插件的 effect:插件卸载(或热重载)时,中间件随之移除。next() 返回的响应总可以修改响应头,即使它来自 fetch() 或 Response.redirect()。前端应用同样可以使用中间件,例如统一添加响应头。

官方的中间件插件有各自的位置,应用自己的中间件(默认 0)在它们之内,能读到会话与登录用户:

order插件
-400@cormijs/plugin-security:安全响应头
-300@cormijs/plugin-cors:跨域
-200@cormijs/plugin-rate-limit:限流
-100@cormijs/plugin-session:state.session
-90@cormijs/plugin-auth:state.user

见 会话、鉴权与常用中间件。

请求的上下文 ​

中间件的第二个参数,与接口的 ApiContext、loader 的 context 一样,包含:

成员说明
state请求级的状态,见下文
ip客户端的地址;应用在代理之后时是代理的地址,客户端在 x-forwarded-for 中

读写 cookie 用 @cormijs/cormi 的 getCookies(request) 与 setCookie(response, name, value, options);一个响应可以设置多个 cookie。

请求状态 ​

每个请求有一个 state 对象,中间件、接口与页面的 loader 读写的是同一个对象。会话、登录用户这类信息由中间件写入,之后的处理直接读取。state 的类型由声明合并扩展:

ts
declare module '@cormijs/cormi' {
  interface State {
    requestId: string
  }
}

ctx.middleware.use(async (request, { state }, next) => {
  state.requestId = request.headers.get('x-request-id') ?? crypto.randomUUID()
  return next()
})
ts
// server/api/health.ts
export function GET(request: Request, { state }: ApiContext) {
  return { requestId: state.requestId }
}

代理 ​

preset 的 proxy 把请求转发到其他服务器,常用于前端应用对接单独部署的后端:

yaml
- name: '@cormijs/preset'
  config:
    proxy:
      /api:
        target: http://localhost:3000
        changeOrigin: true
        pathRewrite:
          ^/api: ''
        headers:
          x-from: cormi
选项说明
target转发的目标服务器
changeOrigin发送目标服务器的 host;原来的 host 保留在 x-forwarded-host
pathRewrite改写路径,键是正则
headers附加到转发请求的请求头

代理在 dev 与 start 下生效,排在 mock 之后。请求通过 fetch() 转发并以流的形式返回,不支持 WebSocket。

ctx.server ​

需要更底层的控制时,插件可以直接使用 ctx.server 注册路由与 connect 风格的中间件,见 Node 端服务。

以 MIT 许可发布 · 基于 Cordis 4、React 19 与 Vite 7