Rack-Cors导致Fine Uploader预检请求失败问题排查求助
React + Fine Uploader + Rails 5 后端文件上传解决方案
我来帮你梳理下React前端用Fine Uploader对接Rails 5后端上传文件的关键点,结合你当前的中间件配置情况来一步步排查和优化:
一、先把CORS配置做扎实
你已经把Rack::Cors放在中间件第二位,这个位置没问题,但得确保CORS规则配置正确——毕竟跨域上传的核心就是这个。打开config/initializers/cors.rb,检查配置是不是类似这样:
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do # 开发环境可以用通配符,生产环境一定要换成你的前端实际域名,比如'https://your-react-app.com' origins '*' resource '*', headers: :any, # 要包含Fine Uploader用到的所有请求方法,OPTIONS是预检请求必须的 methods: [:get, :post, :put, :patch, :delete, :options], # 暴露这两个响应头,Fine Uploader需要它们处理下载和上传进度 expose: ['Content-Disposition', 'X-Content-Length'] end end
小提示:虽然你现在把
Rack::Cors放在第二位,只要它在ActionDispatch::Static之前就没问题,但用insert_before 0把它设为第一个中间件会更稳妥,避免静态资源请求先被处理导致CORS头没加上。
二、React里的Fine Uploader配置要踩对坑
在你的React组件里初始化Fine Uploader时,有几个关键配置不能漏:
import FineUploaderTraditional from 'fine-uploader-wrappers'; import TraditionalUploader from 'react-fine-uploader-traditional'; const uploader = new FineUploaderTraditional({ options: { request: { endpoint: '/uploads', // 这里填你的Rails后端上传接口路径 // 必须带上Rails的CSRF令牌,不然会被Rails的防护机制拦截 customHeaders: { 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, // 如果Fine Uploader默认的参数名'qqfile'和你Rails控制器里的参数名不一致,在这里映射 params: { file: 'qqfile' } }, cors: { expected: true, // 明确告诉Fine Uploader我们要处理跨域请求 sendCredentials: true // 如果前端和后端域名不同,且需要传递Cookie的话开启这个 }, // 大文件上传建议开分片,避免超时或者服务器限制 chunking: { enabled: true } } }); // 然后在组件里渲染上传组件 function FileUploader() { return <TraditionalUploader uploader={uploader} />; }
三、Rails后端接口要适配Fine Uploader的请求
在Rails里写上传控制器(比如UploadsController)时,要注意参数名和响应格式:
class UploadsController < ApplicationController # 如果已经通过customHeaders传递了CSRF令牌,这个可以不用加;如果没传递,再加上跳过验证 # skip_before_action :verify_authenticity_token, only: [:create] before_action :set_upload, only: [:show, :destroy] def create # 这里的:file对应前面Fine Uploader配置里的params映射,要是没映射就用params[:qqfile] @upload = Upload.new(upload_params) if @upload.save # Fine Uploader需要接收{ success: true }格式的响应 render json: { success: true }, status: :ok else # 失败时要返回错误信息,格式要符合Fine Uploader的要求 render json: { success: false, error: @upload.errors.full_messages.join(', ') }, status: :unprocessable_entity end end private def set_upload @upload = Upload.find(params[:id]) end def upload_params params.require(:upload).permit(:file) end end
四、中间件顺序和Webpack代理的小细节
你的当前中间件顺序是:
use Webpacker::DevServerProxyuse Rack::Corsuse Rack::Sendfile- ...
这个顺序没问题,但要注意Webpacker::DevServerProxy会不会把上传请求拦截到webpack dev server。打开config/webpacker.yml,给dev server的proxy加个排除规则:
development: dev_server: proxy: enabled: true host: localhost port: 3000 public: localhost:3000 headers: Host: localhost:3000 # 把上传接口排除在外,让请求直接到Rails后端 exclude: ['/uploads']
这样就能保证上传请求不会被webpack代理走,而是正确到达Rails后端,CORS中间件也能正常处理跨域头了。
内容的提问来源于stack exchange,提问作者Don Giulio
相关产品推荐
相关产品推荐

