React+Rails前后端POST请求触发ActionController::InvalidAuthenticityToken错误如何解决
问题根因
从Rails日志可以直接定位错误触发原因:
- 你的前端服务运行在
http://localhost:3000,Rails后端运行在http://localhost:3006,属于跨域请求 - Rails默认开启CSRF(跨站请求伪造)保护,非GET类请求会校验Origin头或者请求携带的CSRF令牌,前后端分离架构下默认不会携带CSRF令牌,同时Origin不匹配就会抛出
ActionController::InvalidAuthenticityToken错误
解决方案
方案1:纯API服务场景直接跳过CSRF校验
如果你的Rails应用仅作为前后端分离架构的API服务,不需要处理传统浏览器表单提交,可以直接关闭对应接口的CSRF校验:
在PlayersController中添加跳过校验的逻辑即可:
class PlayersController < ApplicationController # 新增这一行,跳过当前控制器所有接口的CSRF校验 skip_before_action :verify_authenticity_token def update_or_create # 原有逻辑不变 puts ("Update or Create hit") @player = Player.create_or_find_by(name: player_params[:name]) puts (player_params) @player.update(class: player_params[:class], lvl: player_params[:level], atk: player_params[:atk], sAtk: player_params[:sAtk], def: player_params[:def], sDef: player_params[:sDef], spd: player_params[:spd], hp: player_params[:hp]) # 注意你原有代码的render写法有语法错误,应该是render json: @player而非json{@player} render json: @player end private def player_params params.require(:player).permit(:name, :inv_hash, :lvl, :name, :class, :atk, :def, :sAtk, :sDef, :spd, :hp, :move_distance) end end
如果整个应用都是API服务,可以直接把skip_before_action :verify_authenticity_token加到ApplicationController中,全局生效。
方案2:保留CSRF校验的配置方式
如果需要保留CSRF校验能力,需要完成两步配置:
- 配置Rails CORS规则允许前端域名访问
安装rack-corsgem,在config/initializers/cors.rb中添加如下配置:
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'http://localhost:3000' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
- 前端请求携带CSRF令牌
Rails会默认把CSRF令牌存在名为XSRF-TOKEN的cookie中,前端发送请求时从cookie中读取该值,添加到请求头的X-CSRF-Token字段即可,修改你的fetch请求配置:
const playerPOST = ({ method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json", // 新增CSRF令牌头,可通过js-cookie等库读取cookie中的XSRF-TOKEN值 "X-CSRF-Token": Cookies.get('XSRF-TOKEN') }, body: JSON.stringify({ // 建议主动把参数包在player字段下,避免参数包装规则异常导致参数校验失败 player: { atk: playerObj.atk, sAtk: playerObj.sAtk, def: playerObj.def, sDef: playerObj.sDef, spd: playerObj.spd, hp: playerObj.hp, name: playerObj.name } }) })
内容的提问来源于stack exchange,提问作者user17306847
相关产品推荐
相关产品推荐

