Rails session在Chrome 67及更低版本中无法持久化问题排查
问题根因
Chrome 67及更低版本session无法持久化的问题,是Fetch API的默认配置差异导致的:
- Chrome 68及以上版本,Fetch API的
credentials参数默认值为same-origin,同源请求会自动携带、存储Cookie - Chrome 67及更低版本,Fetch API的
credentials参数默认值为omit,所有请求默认不会携带、也不会存储响应返回的Cookie
Rails的session默认依赖Cookie存储,POST请求设置session后返回的Set-Cookie响应头在低版本Chrome中被忽略,后续GET请求也不会携带session Cookie,因此读取不到之前设置的session值。
解决方案
修改前端Fetch请求配置,显式指定credentials参数即可:
fetch('/api/set', { method: 'POST', credentials: 'same-origin' // 新增这一行 }) .then((r) => r.json()) .then((r) => { console.log('SET: ', r); fetch('/api/get', { credentials: 'same-origin' // GET请求也需要添加该配置 }) .then((r) => r.json()) .then((r) => console.log('GET: ', r)); });
修改后在所有Chrome版本中都能正常读写session。
复现说明(供排查参考)
最小复现项目可按以下步骤运行:
- 将如下代码保存为
config.ru文件:
require 'bundler/inline' gemfile(true) do source 'https://rubygems.org' gem 'rails', '~> 5.0.6' end require 'rails' require 'action_controller/railtie' class TestApp < Rails::Application config.eager_load = 'development' config.consider_all_requests_local = true config.secret_key_base = '669846b267cea64315663e4f5c124096' config.secret_token = '9c9846b2f7cea64315503e4f5c124094' routes.append do get '/' => 'api#index' post '/api/set' => 'api#set' get '/api/get' => 'api#get' end end class ApiController < ActionController::Base HTML_STRING = <<-EOF <script> fetch('/api/set', { method: 'POST' }) .then((r) => r.json()) .then((r) => { console.log('SET: ', r); fetch('/api/get') .then((r) => r.json()) .then((r) => console.log('GET: ', r)); }); </script> EOF def index render :html => HTML_STRING.html_safe end def set session[:x] = 'x' render :json => { :x => session[:x] } end def get render :json => { :x => session[:x] } end end TestApp.initialize! run TestApp
- 执行命令启动服务:
rackup -p 3030 - 不同版本Chrome访问后的控制台输出差异:
- Chrome 68+:
SET: {x: 'x'} GET: {x: 'x'}- Chrome 67及更低版本:
SET: {x: 'x'} GET: {x: null}
内容的提问来源于stack exchange,提问作者dcangulo
相关产品推荐
相关产品推荐

