【踩坑记录】本地一切正常,部署到 Vercel 却报 405 Not Allowed?根因竟是 sharp 版本

发布于 12 天前  37 次阅读


TL;DR:如果你在 Vercel 上的 API 路由莫名其妙返回 405 Not Allowed,而日志里同时出现
Could not load the "sharp" module using the linux-x64 runtime极大概率是 sharp 二进制与 Vercel 运行时不兼容
sharp(以及 @types/sharp锁定到 0.30.4 即可恢复正常。


现场还原

  • 现象:本地(macOS)开发环境下一切正常;部署到 Vercel 后,访问某些 API(例如 /api/reference/upload)直接 405。
  • Vercel 日志
Error: Failed to load external module sharp: Error: Could not load the "sharp" module using the linux-x64 runtime
Possible solutions:
- Ensure optional dependencies can be installed:
    npm install --include=optional sharp
- Ensure your package manager supports multi-platform installation:
    See https://sharp.pixelplumbing.com/install#cross-platform
- Add platform-specific dependencies:
    npm install --os=linux --cpu=x64 sharp
- Consult the installation documentation:
    See https://sharp.pixelplumbing.com/install
    at Context.externalRequire [as x] (.next/server/chunks/[turbopack]_runtime.js:501:15)
    ...
  page: '/api/reference/upload'
  • 额外信息:Vercel 的 Issues 中也有类似报告(如 vercel/vercel#11052),结论指向 sharp 高版本与 Vercel 运行环境不兼容

为什么会是 405?

很多人见到 405 第一反应是「接口方法不匹配」(比如你只实现了 POST,却发了 GET)。
但在 Next.js + Vercel 的实际部署中,当你的路由模块在运行时加载失败(例如 sharp 无法被正确 require/esm import),框架可能在不同层面表现为:

  • 边缘/服务器层返回一个兜底响应(在某些路径下会显得像 405/404),
  • 或者被中间件/路由处理器吞掉异常,表象并非 500。

关键点看日志!一旦日志出现 Could not load the "sharp" module using the linux-x64 runtime,就应当把怀疑点放在 sharp 二进制/依赖 上,而不是路由方法。


根因分析

  • sharp 是原生扩展,依赖 libvips,并为不同平台/架构提供预编译二进制。
  • 本地(macOS + x64/arm64)能跑,并不代表 部署目标(Vercel 的 Linux x64) 也能跑。
  • 某些新版本 sharp 的预编译二进制与 Vercel 的 Linux 运行时/ABI 并不匹配或存在兼容性问题,导致模块加载失败。
  • 结论:在 Vercel 上,sharp 选择 0.30.4 版本是更稳妥的(来自实踩与社区反馈)。

一分钟修复指南

package.json锁定版本(注意同时锁 @types/sharp,避免类型和 API 偏差):

{
  "dependencies": {
    "sharp": "0.30.4"
  },
  "devDependencies": {
    "@types/sharp": "0.30.4"
  }
}

然后清理并重装依赖,确保锁定真正生效(根据包管工具择一):

# npm
rm -rf node_modules package-lock.json
npm i

# pnpm
rm -rf node_modules pnpm-lock.yaml
pnpm i

# yarn
rm -rf node_modules yarn.lock
yarn

重新部署到 Vercel,再次访问 API,预期恢复正常。

小提示:如果你在 monorepo 或多包管理下(pnpm workspaces / turborepo),请确保 所有用到 sharp 的包都锁同一版本,避免透过 hoist 拉到不兼容版本。


进一步加固(可选)

1) 固定 Node 版本 & 构建环境

package.json 或 Vercel 面板中指定 Node 版本,保持本地/云端一致性,减少 ABI 误差:

{
  "engines": {
    "node": "20.x"
  }
}

2) 避免“跨平台安装”踩坑

如果你在 非 Linux 本地安装依赖(macOS/Windows),再把锁文件直接拿去 Linux 构建,有时会命中不同二进制选择策略。
在 CI 或 Vercel 上总是用 Linux 环境安装(Vercel 默认如此),并避免在本地打包 node_modules 一起上传。

3) 显式作为依赖安装

确保 sharpdependencies,而不是仅在 devDependencies
服务端运行期需要它,不能只在开发依赖里

4) 彻底确认二进制

极端情况下可在 postinstall 强制重建(一般不必):

npm rebuild sharp --platform=linux --arch=x64

验证清单(Checklist)

  • [ ] Vercel 日志不再出现 Could not load the "sharp" module using the linux-x64 runtime
  • [ ] API 路由(例如 /api/reference/upload)本地与线上行为一致
  • [ ] package.jsonsharp@types/sharp 均为 0.30.4
  • [ ] 锁文件与实际安装的版本一致(npm ls sharp / pnpm list sharp / yarn why sharp
  • [ ](可选)固定 Node 版本,避免环境漂移

常见误区 Q&A

Q1:405 一定是路由方法写错吗?
不一定。模块加载失败(尤其是原生扩展)也会导致框架层面的异常返回,表象可能并非 500。见文首日志为判断依据。

Q2:我改成 sharp@latest 不是更好吗?
不一定。以 Vercel 当前的 Linux 运行环境为准。实踩与社区反馈表明 0.30.4 在 Vercel 上更稳定。
(如果后续 Vercel/Sharp 官方更新环境或发布兼容指引,再评估升级。)

Q3:Next/Image 也用到了 sharp,我需要特别配置吗?
只要项目里锁定 sharp@0.30.4,Next.js 服务端用到的那份 sharp 也会落在这个版本,通常无需额外配置。

Q4:我把 API 路由迁去 Edge Functions 能绕过吗?
Edge 环境限制更多,更不建议在 Edge 使用依赖原生二进制的库。需要图像处理时优先放在 Node.js/Serverless 侧。


参考


结语

这类「本地一切正常,线上直接 405」的问题,不要只盯着路由方法。遇到原生扩展(如 sharp)相关的错误日志时,先验证二进制兼容性
当前实践:在 Vercel 上锁定 sharp0.30.4,稳!


A Student on the way to full stack of Web3.