Rails应用重定向使用OPTIONS而非GET的原因排查
在Rails 7.0.8.4(Ruby 2.7.8)环境中,执行destroy方法登出后重定向到SSO登出地址时,浏览器发起OPTIONS请求而非GET,导致目标应用抛出路由错误,可能的原因如下:
1. 前端采用AJAX类请求触发跨域预检
如果前端是通过AJAX(如axios、fetch)或类似异步方式调用destroy接口,由于跨域访问SSO服务,浏览器会先发送OPTIONS预检请求确认是否允许跨域操作。此时destroy方法返回的重定向会被AJAX自动跟随,但浏览器仍会用OPTIONS请求访问SSO的logout地址,而目标服务未配置该方法的路由,从而报错。
解决思路:让前端改用普通表单提交或页面跳转(如a标签)发起请求,避免使用AJAX;若必须用AJAX,需在SSO服务端配置OPTIONS方法的CORS支持。
2. Rails Turbo的默认行为干扰
Rails 7默认启用Turbo,它会将多数常规请求转换为Turbo风格的异步请求,跨域场景下同样会触发OPTIONS预检。即使你写的是普通链接或表单,Turbo也可能将其转为异步请求,导致后续重定向时发起OPTIONS请求。
解决思路:在触发登出的元素上添加data-turbo="false"属性,强制浏览器发起普通的同步请求,绕过Turbo的处理。示例:
<%= link_to '登出', destroy_session_path, method: :delete, data: { turbo: false } %>
3. 跨域资源共享(CORS)配置缺失
当你的应用与SSO服务属于不同域名时,浏览器会对跨域请求执行预检流程。即便重定向目标是GET请求,只要请求发起方式是异步类型,浏览器就会先发送OPTIONS请求到重定向地址,验证跨域权限。若SSO服务未针对OPTIONS方法配置对应路由和CORS响应头,就会抛出路由错误。
解决思路:在SSO服务端的logout路由中添加OPTIONS方法支持,并配置正确的CORS响应头(如Access-Control-Allow-Origin、Access-Control-Allow-Methods),允许发起跨域请求的域名访问。
附:相关代码与错误日志
你的destroy方法代码:
def destroy sign_out redirect_to "#{YAML.load_file("#{Rails.root}/config/sso.yml")[Rails.env]["provider_url"]}/logout?redirect=#{root_url}", allow_other_host: true end
目标应用错误日志:
Started OPTIONS "/logout?redirect=http://localhost:3009/" for ::1 at 2024-09-18 15:16:29 -0300 ActionController::RoutingError (No route matches [OPTIONS] "/logout"):
内容的提问来源于stack exchange,提问作者Wallace Nascimento

