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

Nuxt3前端与Symfony后端上传文件时如何避免CORS错误

Nuxt3前端与Symfony后端上传文件时如何避免CORS错误

我明白你现在被跨域上传文件的问题卡住了,咱们一步步拆解问题,把这个CORS错误解决掉!

首先看你遇到的错误:Response to preflight request doesn't pass access control check: It does not have HTTP ok status. 这个问题核心是浏览器的预请求(OPTIONS请求)没被后端正确处理——浏览器在发送POST这类非简单请求前,会先发送OPTIONS请求确认后端允许跨域,而你的Symfony路由目前只接受POST方法,所以OPTIONS请求进来后返回了错误状态,直接被浏览器拦截了。

另外你的前端代码也有两个小问题需要调整,咱们先改前端:

第一步:修复Nuxt3前端代码

注意这两个关键点:

  1. 不要手动设置Content-Type: multipart/form-data——当你用FormData作为请求体时,浏览器会自动生成包含boundary的正确Content-Type,手动设置反而会破坏这个结构。
  2. Access-Control-Allow-Origin是后端返回给前端的响应头,你在请求里加这个完全没用,反而可能干扰请求。

修改后的代码如下:

let file = ref<File | null>();

const onSelectFile = (event: any): void => {
  file.value = event.target.files[0];
}

const onSaveBook = async () => { // 改成async,方便用await处理响应
  try {
    if (!file.value) return;

    const formData = new FormData();
    formData.append('file', file.value);

    const response = await fetch('http://localhost:8070/upload-book', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        // 移除多余的Content-Type和Access-Control-Allow-Origin
      },
      body: formData,
    });

    // 新增:处理后端响应,方便排查问题
    const result = await response.json();
    console.log('上传结果:', result);
  } catch (error) {
    console.error('上传出错:', error);
  }
}

第二步:修复Symfony后端的CORS处理

现在重点处理后端的预请求和跨域响应头:

方法一:手动在控制器处理(快速测试用)

先修改你的路由,允许OPTIONS方法,并且在控制器里直接处理OPTIONS请求:

#[Route('/upload-book', name: 'app_upload_book', methods: ['POST', 'OPTIONS'])]
public function newBook(Request $request): JsonResponse
{
    // 先处理OPTIONS预请求,直接返回200 OK
    if ($request->isMethod('OPTIONS')) {
        $response = new JsonResponse(null, Response::HTTP_OK);
        // 添加跨域响应头
        $response->headers->set('Access-Control-Allow-Origin', 'http://localhost:8060');
        $response->headers->set('Access-Control-Allow-Methods', 'POST, OPTIONS');
        $response->headers->set('Access-Control-Allow-Headers', 'Accept, Content-Type');
        return $response;
    }

    $file = $request->files->get('file');

    if ($file) {
        $fileName = uniqid() . '.' . $file->getClientOriginalExtension();
        $file->move($this->getParameter('kernel.project_dir') . '/public/uploads', $fileName);

        $response = new JsonResponse('File uploaded successfully', Response::HTTP_OK);
        // 同样添加跨域响应头
        $response->headers->set('Access-Control-Allow-Origin', 'http://localhost:8060');
        return $response;
    }

    $response = new JsonResponse('No file uploaded', Response::HTTP_BAD_REQUEST);
    $response->headers->set('Access-Control-Allow-Origin', 'http://localhost:8060');
    return $response;
}

方法二:全局事件监听器(更优雅,适合多个接口)

如果你的项目有多个跨域接口,手动每个控制器加头太麻烦,可以写一个全局的响应事件监听器,自动给所有响应加上CORS头:

  1. 创建监听器文件:src/EventListener/CorsListener.php
namespace App\EventListener;

use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpFoundation\Response;

class CorsListener
{
    public function onKernelResponse(ResponseEvent $event): void
    {
        $response = $event->getResponse();
        $request = $event->getRequest();

        // 允许你的Nuxt前端域名跨域,生产环境建议不要用*,指定具体域名
        $response->headers->set('Access-Control-Allow-Origin', 'http://localhost:8060');
        // 允许的请求方法
        $response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
        // 允许的请求头
        $response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Accept');
        // 如果需要带Cookie跨域,打开下面这行
        // $response->headers->set('Access-Control-Allow-Credentials', 'true');

        // 处理OPTIONS预请求,直接返回200
        if ($request->isMethod('OPTIONS')) {
            $response->setStatusCode(Response::HTTP_OK);
        }
    }
}
  1. 在config/services.yaml里注册这个监听器:
services:
    App\EventListener\CorsListener:
        tags:
            - { name: kernel.event_listener, event: kernel.response }

方法三:使用NelmioCorsBundle(生产环境推荐)

如果是正式项目,最省心的方式是用Symfony官方推荐的nelmio/cors-bundle,安装后通过配置文件就能统一管理所有跨域规则:

  1. 安装Bundle:
composer require nelmio/cors-bundle
  1. 在config/packages/nelmio_cors.yaml里配置:
nelmio_cors:
    defaults:
        origin_regex: false
        allow_origin: ['http://localhost:8060']
        allow_methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
        allow_headers: ['Content-Type', 'Accept']
        expose_headers: []
        max_age: 3600
    paths:
        '^/upload-book': ~
        # 可以添加其他需要跨域的接口路径

这样Bundle会自动处理所有OPTIONS预请求,并添加正确的CORS响应头,不用手动写代码。

最后总结一下关键点

  • 前端别瞎加Content-Type和Access-Control-Allow-Origin请求头,交给浏览器和后端处理
  • 后端必须处理OPTIONS预请求,并且返回带正确CORS头的200响应
  • 生产环境尽量用CORS Bundle来统一管理,避免手动维护的麻烦

备注:内容来源于stack exchange,提问作者mono ranjan das

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:33:01