配置Nginx与Docker实现React+Rails路由,解决/api重定向循环问题
解决Nginx+Docker下React前端与Rails API的/api路由重定向循环问题
核心问题分析
重定向循环通常由两个原因导致:
- Rails路由未正确匹配/api前缀,返回301重定向到带斜杠的路径,Nginx再次转发后重复触发
- Nginx的
proxy_pass配置错误,导致路径转发异常,触发Rails的路由重定向
步骤1:修正Rails路由配置
确保Rails明确处理/api前缀的请求,且关闭不必要的尾斜杠重定向:
- 在
config/routes.rb中,用scope或namespace定义/api路由,并禁用尾斜杠重定向:
Rails.application.routes.draw do # 禁用尾斜杠重定向,避免Rails自动返回301 scope '/api', trailing_slash: false do # 示例API路由 resources :users, only: [:index, :show] get '/health', to: 'health#check' end end
- 若全局需要关闭尾斜杠重定向,可在
config/application.rb中添加:
config.action_controller.default_url_options = { trailing_slash: false }
步骤2:修复Nginx配置
关键是保证proxy_pass的路径转发正确,同时传递必要的请求头给Rails:
以下是完整的nginx.conf示例:
server { listen 80; server_name example.com; # 处理/api开头的请求,转发到Rails容器 location /api { # 注意:proxy_pass结尾不要加斜杠,否则Nginx会截断/api前缀 proxy_pass http://rails:3000; # 传递真实请求的Host头,避免Rails生成错误的URL proxy_set_header Host $host; # 传递客户端IP proxy_set_header X-Forwarded-For $remote_addr; # 传递请求协议(若使用HTTPS,需修改为$scheme或直接写https) proxy_set_header X-Forwarded-Proto $scheme; } # 处理React前端请求,支持React Router的单页路由 location / { root /usr/share/nginx/html; # 优先匹配静态文件,匹配不到则返回index.html(React路由接管) try_files $uri $uri/ /index.html; } }
Nginx配置的关键注意点:
- 禁止在
proxy_pass结尾加斜杠:如果写成http://rails:3000/,Nginx会把/api/users转发为/users,Rails匹配不到会返回301重定向到/api/users/,触发循环。 - 传递正确的请求头:如果Rails开启了
force_ssl,必须设置X-Forwarded-Proto为https,否则Rails会强制重定向到HTTPS,导致循环。
步骤3:Docker Compose配置验证
确保所有服务在同一网络下,容器名称与Nginx配置中的地址一致:
version: '3.8' services: nginx: image: nginx:alpine ports: - "80:80" # 若使用HTTPS,添加443端口映射 # - "443:443" volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf # 挂载React构建后的静态文件目录 - ./react/build:/usr/share/nginx/html depends_on: - react - rails networks: - app-network react: build: ./react # React项目的Dockerfile需完成构建,输出到build目录 # 示例Dockerfile: # FROM node:18-alpine # WORKDIR /app # COPY package*.json ./ # RUN npm install # COPY . . # RUN npm run build # CMD ["cp", "-r", "build/*", "/usr/share/nginx/html/"] networks: - app-network rails: build: ./rails environment: - RAILS_ENV=production - DATABASE_URL=postgres://user:password@db:5432/app_db # Rails服务器需监听0.0.0.0,否则容器外无法访问 # 示例puma.rb配置:bind 'tcp://0.0.0.0:3000' networks: - app-network networks: app-network: driver: bridge
最后排查事项
- 清除浏览器缓存:301是永久重定向,浏览器会缓存旧的重定向规则,修改配置后用隐私窗口测试。
- 检查Rails日志:查看Rails容器的日志,确认请求是否正确到达,以及重定向的原因。
- HTTPS场景适配:若使用HTTPS,需在Nginx中配置SSL证书,并将
X-Forwarded-Proto设置为https,同时确保Rails的config.force_ssl = true(或根据需求配置)。
内容的提问来源于stack exchange,提问作者Hamdi Huntürk
相关产品推荐
相关产品推荐

