如何实现独立Docker容器中Express API与React的正常通信
故障根因
package.json中配置的proxy规则是Create React App开发服务器专属能力,仅在本地执行npm start运行开发服务时生效。当前配置是将React构建产物放到Nginx中托管静态文件,开发服务器全程不运行,这条代理规则在构建完成后就完全失效。- 容器环境中的
localhost指向容器自身的回环地址,和宿主机、其他容器完全隔离。就算代理规则正常生效,React容器内的localhost:5000也只会访问React容器自身的5000端口,根本无法触达同网络下的Express容器。 - 宿主机浏览器能直接访问
localhost:5000打开Express页面,是因为compose配置中把Express容器的5000端口映射到了宿主机,这是宿主机到容器的访问通路,和容器间内部通信是完全独立的两条链路。
正确配置方案
1. 配置Nginx反向代理替代CRA开发代理
因为生产环境用Nginx托管React静态文件,直接在Nginx层做接口转发,替代原来开发环境的proxy规则。
首先在React项目根目录新建nginx.conf配置文件:
server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html index.htm; # 适配前端路由,避免页面刷新404 location / { try_files $uri $uri/ /index.html; } # 匹配接口请求转发到Express服务 location /api/ { # 直接使用docker-compose定义的服务名作为访问域名,桥接网络会自动做DNS解析 proxy_pass http://api-server:5000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
修改React项目的Dockerfile,把自定义Nginx配置拷贝到镜像内覆盖默认配置,修改后完整内容如下:
FROM node:17 as build WORKDIR /code COPY package*.json ./ RUN npm install COPY . . RUN npm run build FROM nginx:1.12-alpine COPY --from=build /code/build /usr/share/nginx/html # 新增:拷贝自定义Nginx配置 COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
2. 调整前端接口请求路径
前端所有fetch请求统一增加/api前缀,比如原请求路径/user/list改为/api/user/list,Nginx识别到/api开头的请求会自动转发到Express服务,不会当成静态文件处理。
如果不想修改现有请求路径,可以调整Nginx的location匹配规则,直接匹配你现有接口的路径前缀做转发即可,核心逻辑是区分开静态资源请求和接口请求。
3. 优化docker-compose配置
两个服务已经加入同一个自定义桥接网络,容器间内部通信不需要把Express端口暴露到宿主机,去掉ports映射可以避免端口对外暴露带来的安全风险,调整后完整配置如下:
version: "3" services: react-app: build: ./react # 替换为你本地React项目的实际目录路径 stdin_open: true ports: - "3000:80" networks: - react-express depends_on: - api-server api-server: build: ./express # 替换为你本地Express项目的实际目录路径 # 移除5000端口的宿主机映射,仅允许内部网络访问 networks: - react-express networks: react-express: driver: bridge
注意:所有配置修改完成后,需要执行
docker-compose up --build重新构建镜像再启动,不要使用之前构建的旧镜像,否则新配置不会生效。原package.json里的proxy配置可以直接删除,生产环境下该配置无任何作用。
验证逻辑
- 容器内部通信走Docker自定义桥接网络的内置DNS,直接用compose中定义的服务名
api-server即可访问Express服务,不需要依赖localhost,也不需要走宿主机端口映射。 - 浏览器访问时所有请求先打到React容器的Nginx服务,静态资源请求直接返回前端构建产物,接口请求由Nginx转发到Express容器,全程不存在跨域问题。
内容的提问来源于stack exchange,提问作者CodeNoob
相关产品推荐
相关产品推荐

