React前端跨域问题排查:Docker多容器架构下CORS错误
Docker容器部署前后端应用的CORS问题排查与解决
问题描述
使用React前端、Node.js后端、PostgreSQL、Nginx四个独立Docker容器部署应用,尝试通过Nginx代理实现前后端通信时持续出现CORS错误。已配置Nginx的CORS响应头、后端cors中间件,耗时两天仍未解决,附上所有相关配置文件与代码片段,请求排查解决该跨域问题。
相关配置文件与代码片段
docker-compose 文件
version: "3.8" #Update the connection among these microservices before starting the container. services: nginx: build: context: ./nginx dockerfile: Dockerfile ports: - 80:80 depends_on: - frontend - api links: - frontend - api frontend: build: context: ./frontend dockerfile: Dockerfile ports: - 3000:3000 depends_on: - api volumes: - ./frontend:/app api: build: context: ./api dockerfile: Dockerfile ports: - 5001:5001 volumes: - ./api:/app depends_on: - db links: - db db: image: postgres:15.3-alpine3.18 ports: - 5432:5432 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres
nginx default.config
server { listen 80; listen [::]:80; server_name localhost; #access_log /var/log/nginx/host.access.log main; # location / { # root /usr/share/nginx/html; # index index.html index.htm; # } location / { proxy_pass http://frontend:3000; } location /api { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; proxy_pass http://api:5001; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
Dockerfile for nginx
FROM nginx:1.25.1-alpine3.17 RUN rm /etc/nginx/conf.d/default.conf COPY default.conf /etc/nginx/conf.d/default.conf EXPOSE 80
Dockerfile for Frontend
FROM node:18.16.1-alpine3.18 RUN mkdir -p /app WORKDIR /app EXPOSE 3000 CMD echo 1; npm install; echo 2; npm run start
Dockerfile for backend
FROM node:18.16.1-alpine3.18 RUN mkdir -p /app WORKDIR /app RUN npm install nodemon -g EXPOSE 5001 CMD echo 1; npm install; echo 2; npm start
后端代码片段
import express, { Application } from "express"; import cors, { CorsOptions } from "cors"; import session from 'express-session'; import Routes from "./routes"; import Database from "./db"; import seedDatabse from './config/seedDB'; export default class Server { constructor(app: Application) { this.config(app); this.syncDatabase(); new Routes(app); } private config(app: Application): void { const corsOptions: CorsOptions = { origin: ['*'], // credentials: true, }; app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(session({ secret: 'secret', resave: false, saveUninitialized: false })); } private async syncDatabase(): Promise<void> { const db = new Database(); await db.sequelize?.sync(); seedDatabse(); } }
Frontend api.service.ts 请求代码
export const apiRequests: any = async (uri: string, method: string, body: any) => { const data = await fetch(`http://localhost/api/${uri}`, { method, headers: { 'Content-Type': 'application/json', }, body: body ? JSON.stringify(body) : null }) .then((res: Response) => res.json()) .then((resp: any) => { return resp; }); return data; };
Frontend package.json 片段
{ "proxy": "http://api:5001", "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" } }
问题排查与修复方案
1. 补全Nginx OPTIONS请求处理
浏览器跨域请求前会发起OPTIONS预飞请求,当前Nginx未处理该请求导致CORS失败。修改/api位置的配置:
location /api { # 专门处理OPTIONS预飞请求 if ($request_method = OPTIONS) { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } # 常规请求的CORS头,添加always确保错误响应也携带 add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; proxy_pass http://api:5001; }
2. 修复Dockerfile语法错误
多个Dockerfile存在命令未换行的问题,导致容器构建失败:
Nginx Dockerfile修复:
FROM nginx:1.25.1-alpine3.17 RUN rm /etc/nginx/conf.d/default.conf COPY default.conf /etc/nginx/conf.d/default.conf EXPOSE 80
Frontend Dockerfile修复:
FROM node:18.16.1-alpine3.18 RUN mkdir -p /app WORKDIR /app EXPOSE 3000 CMD echo 1; npm install; echo 2; npm run start
Backend Dockerfile修复:
FROM node:18.16.1-alpine3.18 RUN mkdir -p /app WORKDIR /app RUN npm install nodemon -g EXPOSE 5001 CMD echo 1; npm install; echo 2; npm start
3. 优化前端请求路径
将请求路径改为相对路径,避免写死域名,并移除无效的proxy配置:
export const apiRequests: any = async (uri: string, method: string, body: any) => { const data = await fetch(`/api/${uri}`, { method, headers: { 'Content-Type': 'application/json', }, body: body ? JSON.stringify(body) : null }) .then((res: Response) => res.json()) .then((resp: any) => { return resp; }); return data; };
删除package.json中的"proxy": "http://api:5001"字段,该配置仅在React开发服务器生效,Docker环境下依赖Nginx代理即可。
4. 消除CORS配置冲突
后端与Nginx同时配置CORS可能导致响应头重复,建议保留Nginx的CORS配置,移除后端的cors中间件:
// 后端config方法中删除以下代码 // const corsOptions: CorsOptions = { // origin: ['*'], // // credentials: true, // }; // app.use(cors(corsOptions));
5. 修正docker-compose语法
原文件中services字段重复,已在上方代码块中修正,确保yaml语法合法。
验证步骤
- 停止所有容器:
docker-compose down - 重新构建并启动容器:
docker-compose up --build - 访问
http://localhost打开前端,测试API请求是否正常,检查浏览器控制台是否存在CORS错误。
内容的提问来源于stack exchange,提问作者Ram Budha
相关产品推荐
相关产品推荐

