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

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语法合法。

验证步骤

  1. 停止所有容器:docker-compose down
  2. 重新构建并启动容器:docker-compose up --build
  3. 访问http://localhost打开前端,测试API请求是否正常,检查浏览器控制台是否存在CORS错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:27:04