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

Kubernetes环境下FastAPI+React应用文件上传遇CORS问题求助

问题:Kubernetes环境下React+FastAPI文件上传遭遇CORS跨域问题

尝试在Kubernetes环境中实现React前端与FastAPI后端配合完成文件上传至数据库,但反复遇到CORS跨域问题,查阅多篇资料后仍未解决。

相关代码与配置

FastAPI代码

from fastapi import (
    APIRouter,
    Depends,
    HTTPException,
    UploadFile,
    File
)
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
import httpx

app = FastAPI()

# Add CORS middleware to the app (not to the router)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Allows all origins
    allow_credentials=True,
    allow_methods=["*"],  # Allows all methods
    allow_headers=["*"],  # Allows all headers
)

router = APIRouter(
    prefix="/api",
    tags=["api"],
    responses={404: {"description": "404 Page Not Found"}},
)

@router.get("/")
async def read_items():
    return "<h1>Page</h1>"


@router.post("/upload")
async def upload(file: UploadFile = File(...)):
    print("Upload")

app.include_router(router)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=20000)

FastAPI的Kubernetes Deployment配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
  labels:
    app: api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: api:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 12980
          name: web

FastAPI的Kubernetes Service配置

apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  selector:
    app: api
  ports:
    - name: http
      protocol: TCP
      port: 20000
      targetPort: 20000

Nginx代理配置(尚未转发请求,先验证预检请求)

server {
   listen 80;
   server_name api.localhost;

   add_header 'Access-Control-Allow-Origin' $http_origin;
   add_header 'Access-Control-Allow-Credentials' 'true';
   add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
   add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';

  location / {

     if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain charset=UTF-8';
      add_header 'Content-Length' 0;
      add_header 'Access-Control-Allow-Origin' $http_origin;
      add_header 'Access-Control-Allow-Credentials' 'true';
      add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
      add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
    }

    proxy_redirect off;
    proxy_set_header host $host;
    proxy_set_header X-real-ip $remote_addr;
    proxy_set_header X-forward-for $proxy_add_x_forwarded_for;
    #   proxy_pass http://cos-service.default.svc.cluster.local:20000/;
  }
}

Nginx的Kubernetes Deployment配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-cors
  labels:
    app: nginx-cors
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-cors
  template:
    metadata:
      labels:
        app: nginx-cors
    spec:
      containers:
      - name: nginx-cors
        image: nginx-cors:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 80
          name: nginx

Nginx的Kubernetes Service配置

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx-cors
  ports:
    - name: http
      protocol: TCP
      port: 11999
      targetPort: 80

React前端代码

import React, { useState, ChangeEvent, FormEvent } from 'react';
import axios from 'axios';

const FileUpload: React.FC = () => {
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [uploadProgress, setUploadProgress] = useState<number>(0);

  const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
    if (event.target.files && event.target.files.length > 0) {
      setSelectedFile(event.target.files[0]);
    }
  };

  const handleUpload = async (event: FormEvent) => {
    event.preventDefault();

    if (!selectedFile) {
      alert('Please select a file first');
      return;
    }

    const formData = new FormData();
    formData.append('file', selectedFile);
    console.log("formdata ", formData);

    try {
      const response = await axios.post('http://nginx-svc:11999/', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        onUploadProgress: (progressEvent) => {
          const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
          setUploadProgress(percentCompleted);
        },
      });
      if (response.status === 201) {
        alert('File uploaded successfully');
      } else {
        alert('File upload failed');
      }
    } catch (error) {
      console.error('Error uploading file:', error);
      alert('Error uploading file');
    }
  };

  return (
    <div>
      <form onSubmit={handleUpload}>
        <input type="file" onChange={handleFileChange} />
        <button type="submit">Upload File</button>
      </form>
      {uploadProgress > 0 && <p>Upload Progress: {uploadProgress}%</p>}
    </div>
  );
};

export default FileUpload;

错误现象

点击上传按钮后,浏览器出现CORS错误,Firefox的网络调试信息如下:

  • CORS错误提示
  • 网络请求CORS详情
  • 预检请求详情

恳请帮忙排查问题所在。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:47:03