You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子域名调用Express文件上传API时出现CORS错误求助

子域名调用Express文件上传API触发CORS错误的解决办法

问题详情

错误提示:
Access to XMLHttpRequest at 'https://api.mysite.com/api/uploadfile' from origin 'https://sub.mysite.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

  • 环境:子域名https://sub.mysite.com(Angular前端)调用主域名https://api.mysite.com(Express后端)的API
  • 异常:其他API接口正常,仅文件上传路由返回CORS错误
  • 已尝试:查阅相关问题未解决

后端(Express)代码

// 允许所有跨域请求
this.app.use(cors()); 

// 文件上传路由
var upload = multer({ storage: storage });
this.router.post("/", passport.authenticate('jwt', { session: false }),  
                      upload.single('file'), 
                      this.fileController.uploadfile); 

前端(Angular)代码

uploadFile(formData: any): Observable<any> {
    // test 1(已注释)
    // return Axios.post(`${this.apiURL}test`, formData, {
    //     headers: {
    //         'Authorization': this._authService.accessToken,
    //         'Content-Type': 'multipart/form-data' 
    //     }
    // })
    // .pipe(
    //     tap((response: any) => {
    //         console.log("response:", response)
    //     })
    // );

    // test 2(当前使用)
    const httpOptions = {
        headers: new HttpHeaders({ 
            'Authorization': this._authService.accessToken,
            'Content-Type': 'multipart/form-data'   
        })
    };
    return this.http.post<any>(`${this.apiURL}test`, formData, httpOptions)
    .pipe(
        tap((response: any) => {
            console.log("response:", response)
        }),
        catchError(this.handleError)
    );
}

解决步骤

1. 移除前端手动设置的Content-Type

上传FormData时,浏览器会自动生成包含boundary的multipart/form-data头,手动设置会丢失boundary,导致后端Multer无法解析请求,进而返回无CORS头的错误响应。

修正后的前端代码:

uploadFile(formData: any): Observable<any> {
    const httpOptions = {
        headers: new HttpHeaders({ 
            'Authorization': this._authService.accessToken
            // 移除Content-Type设置,由浏览器自动处理
        })
    };
    return this.http.post<any>(`${this.apiURL}test`, formData, httpOptions)
    .pipe(
        tap((response: any) => console.log("response:", response)),
        catchError(this.handleError)
    );
}

2. 调整后端CORS中间件顺序

确保cors()中间件在所有路由、Passport认证、Multer配置之前加载,否则文件上传路由可能无法触发CORS头的设置:

// 先加载CORS中间件(明确指定允许的源,比允许所有更安全)
this.app.use(cors({
    origin: 'https://sub.mysite.com',
    credentials: true // 如果需要携带认证信息或Cookie
}));

// 再加载Passport、路由等
this.app.use(passport.initialize());
this.app.use("/api/uploadfile", this.router);

3. 添加全局错误处理中间件

如果Multer解析失败(比如FormData中没有file字段),Express默认返回的错误响应不会携带CORS头,需要添加全局错误处理确保所有响应都包含CORS头:

this.app.use((err, req, res, next) => {
    res.header('Access-Control-Allow-Origin', 'https://sub.mysite.com');
    res.status(err.status || 500).json({ 
        message: err.message || '服务器内部错误' 
    });
});

4. 验证FormData格式

确保前端构造的FormData中确实包含名为file的字段,与后端upload.single('file')的参数一致:

// 示例:正确构造FormData
const formData = new FormData();
formData.append('file', fileInput.files[0]); // 字段名必须是'file'

内容的提问来源于stack exchange,提问作者wil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:50:17