Ruby on Rails(Heroku+Cloudflare)自定义域名注册报错原因及解决求助
Rails + Heroku + Cloudflare下ActionController::InvalidAuthenticityToken错误的原因与解决办法
问题原因
Cloudflare作为SSL终止服务,会把用户发起的HTTPS请求转换成HTTP转发给Heroku。这导致Rails生成的request.base_url是HTTP协议,但浏览器发送的Origin请求头是HTTPS(因为用户访问的是HTTPS域名)。Rails的CSRF验证机制会对比这两个值的协议、域名等信息,协议不匹配就会触发ActionController::InvalidAuthenticityToken错误,返回422状态码。而Heroku原生域名提交正常,是因为原生域名的请求没有经过Cloudflare的协议转换,协议始终一致。
解决办法
1. 让Rails信任Cloudflare转发头,识别真实请求协议
在config/environments/production.rb中添加以下配置:
# 信任Cloudflare官方源IP段,确保转发头可信 config.action_dispatch.trusted_proxies = %w[173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22] # 开启强制SSL,此时Rails能识别真实的HTTPS请求 config.force_ssl = true
这段配置告诉Rails,来自Cloudflare IP的请求里的X-Forwarded-Proto头是可信的,Rails会用该头的协议生成request.base_url,使其与Origin头的HTTPS协议保持一致。
2. 调整Cloudflare的SSL模式设置
登录Cloudflare后台,进入目标域名的SSL/TLS设置页面:
- 将SSL模式设置为完全(Full)或严格(Full strict),禁用「灵活(Flexible)」模式。灵活模式下Cloudflare到Heroku的请求是HTTP,容易引发协议不匹配问题;完全模式下Cloudflare与Heroku之间也采用HTTPS通信,既安全又能避免头信息冲突。
3. 验证请求头与base_url的一致性
可以临时在控制器中添加调试接口,确认相关参数是否正常:
def check_request_info render plain: <<~TEXT X-Forwarded-Proto: #{request.headers['X-Forwarded-Proto']} Origin: #{request.headers['Origin']} request.base_url: #{request.base_url} TEXT end
部署后访问该接口,确认三个值的协议均为https,即可保证CSRF验证正常通过。
内容的提问来源于stack exchange,提问作者wired for freedom
相关产品推荐
相关产品推荐

