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

React+Nginx+Docker部署后刷新/api路由仅返回JSON的问题

问题描述

通过Docker Compose部署React前端+Nginx,Nginx将/api请求代理至backend:8080/api。正常通过页面按钮跳转访问example.com/api/userlist时,能正常显示页面并获取数据;但直接刷新或手动输入该URL时,返回后端原始JSON数据而非React页面。本地运行React无此问题,仅Nginx部署场景下出现。

相关配置文件

前端Dockerfile

# Base image
FROM node:18.3.0-alpine AS build

# Set working directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy source files
COPY . .

# Build application
RUN npm run build

# New base image
FROM nginx:1.21.0-alpine

# Copy build files from previous stage
COPY --from=build /app/build/ /usr/share/nginx/html/

# start nginx
CMD ["nginx", "-g", "daemon off;"]

Docker Compose文件

version: '3'

services:
  frontend:
    build: ./front-end
    ports:
    - "80:80"
    depends_on:
    - backend
  backend:
    build: ./back-end
    ports:
      - "8080:8080"

当前Nginx配置

server {
    listen       80;
    server_name  localhost;

# Add root directory
    root   /usr/share/nginx/html;

    #access_log  /var/log/nginx/host.access.log  main;

# Add proxy for /api
location /api {
   proxy_pass http://backend:8080/api;
   proxy_set_header Host $host;
}

location / {
   try_files $uri $uri/ /index.html;
}
解决方案

问题核心是:Nginx的location /api会匹配所有以/api开头的请求,包括React客户端路由的/api/userlist。当用户直接刷新或输入该URL时,请求没有前端API请求的特征头,Nginx依然代理到后端返回JSON,而非返回React的index.html让前端路由处理。

解决思路是区分API请求和客户端路由请求,仅对真正的API请求做代理,其余返回React页面让前端路由处理。修改后的Nginx配置如下:

server {
    listen       80;
    server_name  localhost;

    root   /usr/share/nginx/html;

    # 处理/api路径:区分API请求与前端路由
    location /api {
        # 仅当请求接受JSON格式时,代理到后端API
        if ($http_accept ~* "application/json") {
            proxy_pass http://backend:8080/api;
            proxy_set_header Host $host;
            break;
        }
        # 其他情况(前端路由请求)返回index.html
        try_files $uri $uri/ /index.html;
    }

    location / {
        try_files $uri $uri/ /index.html;
    }
}

补充说明

  • 前端axios/fetch发起API请求时,默认会携带Accept: application/json请求头,这也是配置中判断的依据。
  • 如果你的前端API请求未携带该头,可改用AJAX请求标识判断,将if条件替换为:
    if ($http_x_requested_with = "XMLHttpRequest") {
    
  • 确保前端使用BrowserRouter(而非HashRouter),HashRouter路径带#不会触发Nginx路径匹配问题,但URL不够直观。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:22:33