返回
创建于
状态
公开

在 Vite (基于 Connect 中间件框架) 的开发服务器中,server.middlewares.useserver.middlewares.stack.unshift 的区别决定了谁拥有请求的优先处理权

以下是 server.middlewares.stack.unshift 解决的核心问题及深度解析:


1. 解决的核心问题:拦截优先级

Vite 的开发服务器实质上是一个由一系列中间件构成的“洋葱模型”或“管道”。

  • 默认行为 (.use):会将你的中间件排在队列的末尾
  • 强制抢占 (stack.unshift):将你的中间件推到队列的最顶端

为什么要抢占? 因为 Vite 内部注册了许多内置中间件(如 viteIndexHtmlMiddleware, viteSpaFallbackMiddleware, viteStaticMiddleware 等)。如果你的 API 路径刚好和这些内置逻辑冲突,或者你配置了 server.proxy,请求会被它们先行拦截并返回。

例如,如果你请求 /api/auto-icon

  1. 如果不使用 unshift:请求可能先经过 Vite 的静态资源中间件,它发现磁盘上没这个文件,可能会直接返回 404 或重定向到 index.html,你的插件根本没机会运行。
  2. 使用 unshift 后:请求进入服务器的第一时间就会被你的插件捕捉,在它被其他逻辑“吃掉”之前完成处理。

2. 彻底解决 CORS (跨域) 预检失败

这是你之前遇到的 OPTIONS 请求收不到的元凶。

浏览器在发送 POST (JSON) 之前会发送一个 OPTIONS 预检请求。

  • 问题所在:Vite 的某些内置中间件(或你配置的代理)如果发现是一个 OPTIONS 请求且不符合它们的预期,可能会直接返回错误或不带任何 CORS Header 的响应。
  • 解决方案:通过 unshift,你的插件成为了 "CORS 第一守门员"。它在任何其他逻辑干扰之前,率先捕获 OPTIONS 并返回带有 Access-Control-Allow-Origin 等 Header 的 204 状态码。

3. 代码结构拆解

typescript
1server.middlewares.stack.unshift({
2  route: '',        // 匹配所有路径的前缀(我们在 handler 内部根据 requestUrl 精确匹配)
3  handle: handler,  // 你的中间件函数
4})
  • route: '':这意味着任何请求进入服务器时,都会先经过你的这个中间件。这比 .use('/api/auto-icon', handler) 更稳健,因为后者有时会因为 Vite 路径解析的优先级问题被绕过。
  • stack 对象:这是 Connect 框架暴露的底层数组。直接操作它是为了突破 Vite 高层 API 的限制,实现“插队”。

4. 为什么 Vite 7+ 更需要它?

在 Vite 7 以及现代 SSR 框架(如你正在使用的 Pandora 项目涉及的 TanStack Start/Vite SSR)中,中间件的层级变得非常复杂:

  • SSR 中间件 往往具有很高的优先级。
  • 静态资源重定向 逻辑变得更智能。

如果你不使用 unshift,你的插件可能只是在“陪跑”,只有当所有人都处理不了这个请求时,才会轮到它,而通常那时请求已经被拦截或报错了。


💡 技术提醒

虽然 unshift 很强大,但要记住在你的 handler 中:

  1. 精确判断路径:必须判断 if (requestUrl !== '/api/auto-icon') return next(),否则你会拦截掉项目里所有的 JS/CSS 文件加载,导致页面刷不出来。
  2. 及时终止:一旦匹配到业务逻辑(如处理完写入),必须 res.end()不要再调用 next(),防止请求继续往下流向 Vite 的错误处理逻辑。