调用faceLandmarkDetection createDetector时遭遇CORS错误求解
在Next.js项目中调用faceLandmarksDetection.createDetector时触发CORS错误,请求模型资源被浏览器拦截,具体错误信息如下:
Access to fetch at
https://www.kaggle.com/models/mediapipe/face-landmarks-detection/frameworks/tfJs/variations/face-mesh/versions/1/model.json?tfjs-format=file&tfhub-redirect=true(redirected fromhttps://tfhub.dev/mediapipe/tfjs-model/face_landmarks_detection/face_mesh/1/model.json?tfjs-format=file) from originhttp://localhost:3000has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
当前使用的模型初始化代码:
const setupTensorflow = async() => { const faceLandmarksDetection = await import('@tensorflow-models/face-landmarks-detection') const model = faceLandmarksDetection.SupportedModels.MediaPipeFaceMesh const detectorConfig: faceLandmarksDetection.MediaPipeFaceMeshMediaPipeModelConfig = { runtime: 'tfjs' } detector.current = await faceLandmarksDetection.createDetector(model, detectorConfig) }
已尝试在Next.js配置中添加CORS响应头,但未解决问题:
const nextConfig = withSentryConfig({ async headers() { return [ { source: '/', headers: [ { key: 'Access-Control-Allow-Credentials', value: 'true' }, { key: 'Access-Control-Allow-Origin', value: '*' }, // replace this your actual origin { key: 'Access-Control-Allow-Methods', value: 'GET,DELETE,PATCH,POST,PUT' }, { key: 'Access-Control-Allow-Headers', value: 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' } ] } ] }, ... })
解决办法
1. 切换runtime为'mediapipe'
将detectorConfig中的runtime改为'mediapipe',MediaPipe的模型加载逻辑无需经过tfhub跳转,可直接避开CORS限制:
const detectorConfig: faceLandmarksDetection.MediaPipeFaceMeshMediaPipeModelConfig = { runtime: 'mediapipe', solutionPath: 'https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh' }
2. 本地托管模型文件
若必须使用tfjs runtime,可将模型文件下载到本地,通过本地路径加载:
- 下载face-mesh的tfjs模型文件(包含
model.json及相关权重文件) - 将模型文件放置在Next项目的
public目录下,例如public/models/face-mesh/ - 修改配置指定本地模型路径:
const detectorConfig: faceLandmarksDetection.MediaPipeFaceMeshMediaPipeModelConfig = { runtime: 'tfjs', modelUrl: '/models/face-mesh/model.json' }
3. 通过Next.js API路由代理请求
利用Next.js的API路由转发模型请求,绕过浏览器的CORS检查:
- 创建
pages/api/proxy-model.ts文件:
import type { NextApiRequest, NextApiResponse } from 'next' import fetch from 'node-fetch' export default async function handler(req: NextApiRequest, res: NextApiResponse) { const modelUrl = req.query.url as string if (!modelUrl) { return res.status(400).json({ error: '缺少模型地址参数' }) } try { const response = await fetch(modelUrl) const data = await response.json() res.setHeader('Content-Type', 'application/json') res.status(200).json(data) } catch (error) { res.status(500).json({ error: '模型请求失败' }) } }
- 修改模型加载代码,通过代理接口请求:
const detectorConfig: faceLandmarksDetection.MediaPipeFaceMeshMediaPipeModelConfig = { runtime: 'tfjs', modelUrl: '/api/proxy-model?url=https://tfhub.dev/mediapipe/tfjs-model/face_landmarks_detection/face_mesh/1/model.json?tfjs-format=file' }
注意:如果模型包含多个权重文件,这种方式需要额外处理静态资源的代理,相比之下本地托管模型更简便。
内容的提问来源于stack exchange,提问作者John Miller

