You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级至Rails 7后出现CSRF错误,成因是什么?

解决Rails 7中ActiveStorage直传偶发CSRF令牌验证失败问题

一、关于CSRF令牌与部署/重启的关系

  • Rails默认的CSRF令牌绑定到用户session,只要secret_key_base未变更,部署或应用重启不会导致令牌失效。session默认存在cookie中,令牌不会随应用重启改变。即便启用config.action_controller.per_form_csrf_tokens = true(每个表单生成独立令牌),令牌也不会因部署重启失效,仅表单间不通用。

二、直传JS代码的潜在问题

你的代码实现了directUploadWillStoreFileWithXHR钩子,但未确保CSRF令牌被正确添加到XHR请求头。Rails 7中ActiveStorage默认会自动添加CSRF头,但自定义该钩子时,需手动确认头信息设置:

修改directUploadWillStoreFileWithXHR方法,手动添加CSRF令牌头:

@directUploadWillStoreFileWithXHR = (request) ->
  that = this
  @xhrRequest = request
  # 手动添加CSRF令牌请求头
  request.setRequestHeader('X-CSRF-Token', document.querySelector('meta[name="csrf-token"]').content)
  request.upload.addEventListener "progress", (event) ->
    that.directUploadDidProgress(event)

三、大文件上传偶发失败的核心原因

大文件上传耗时久,以下场景会触发令牌验证失败:

  1. 页面闲置过久:用户打开上传页面后长时间未操作,后续发起上传时,页面中的CSRF令牌可能已过期(或因用户在其他标签页登录/退出,导致令牌与当前session不匹配)。
  2. Turbo机制影响:Rails 7默认启用Turbo,Turbo更新页面时会自动刷新meta标签中的CSRF令牌。若用户上传过程中页面被Turbo更新,上传请求仍使用旧令牌,就会触发验证失败。

四、额外优化方案

  • 上传前刷新CSRF令牌:在startUpload方法中,先获取最新令牌,确保上传请求使用当前有效令牌:
@startUpload = (file) ->
  input = document.querySelector('input[type=file]')
  # 刷新CSRF令牌
  document.querySelector('meta[name="csrf-token"]').content = Rails.csrfToken()
  App.Uploader.inProgress = new App.Uploader(file, input.dataset.directUploadUrl, this)
  App.Uploader.inProgress.upload()
  # 后续原有代码保持不变...
  • CSRF错误重试机制:在上传失败回调中检测是否为CSRF错误,刷新令牌后重新发起上传:
@upload = ->
  @directUpload.create (error, blob) =>
    if error
      # 判断是否为CSRF令牌错误
      if error.message.includes?('InvalidAuthenticityToken')
        # 刷新令牌并重试上传
        document.querySelector('meta[name="csrf-token"]').content = Rails.csrfToken()
        @directUpload.create(arguments.callee)
      else
        console.log error
        $('#uploading_done').text('There was an issue uploading your file.').show().css('background', '#D4524B')
        $('#uploading').hide()
    else
      $('input#podcast_file').val(blob.signed_id).closest('form').submitWithRails()

内容的提问来源于stack exchange,提问作者John Pollard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 10:17:35