如何重写Rails ActiveStorage的DirectUploadsController#create添加自定义请求头?
如何重写ActiveStorage::DirectUploadsController以添加自定义请求头?
问题描述
我想了解是否可以重写调用私有方法
direct_upload_json的ActiveStorage::DirectUploadsController#create方法,原代码如下:class ActiveStorage::DirectUploadsController < ActiveStorage::BaseController def create blob = ActiveStorage::Blob.create_before_direct_upload!(blob_args) render json: direct_upload_json(blob) end private ... def direct_upload_json(blob) blob.as_json(root: false, methods: :signed_id).merge(direct_upload: { url: blob.service_url_for_direct_upload, headers: blob.service_headers_for_direct_upload }) end end我需要在请求头中设置
Authorization Bearer <token>以及另一组键值对,请问有什么解决办法?谢谢。
解决方案
当然可以实现这个需求!最稳妥的方式是继承原控制器并重写关键方法,避免直接修改Rails源码带来的兼容性问题。以下是具体步骤:
1. 创建自定义DirectUploads控制器
在app/controllers目录下新建direct_uploads_controller.rb,继承自ActiveStorage的原控制器,然后重写私有方法direct_upload_json来注入自定义请求头:
class DirectUploadsController < ActiveStorage::DirectUploadsController private def direct_upload_json(blob) # 先获取存储服务默认生成的请求头 default_headers = blob.service_headers_for_direct_upload # 合并自定义请求头:这里添加Authorization和你的自定义键值对 custom_headers = default_headers.merge( "Authorization" => "Bearer #{get_auth_token}", "X-Your-Custom-Header" => "your-custom-value" # 替换为实际的键值对 ) # 按照原方法的结构构建响应JSON,替换headers部分 blob.as_json(root: false, methods: :signed_id).merge( direct_upload: { url: blob.service_url_for_direct_upload, headers: custom_headers } ) end # 自定义方法:根据你的业务逻辑获取认证token def get_auth_token # 示例:从当前登录用户获取token,或者从请求头中提取 current_user&.auth_token || request.headers["X-Provided-Token"] end end
2. 更新路由配置
修改config/routes.rb,把ActiveStorage的直接上传路由指向你的自定义控制器:
Rails.application.routes.draw do # 替换默认的direct_uploads路由 direct_uploads route: "direct_uploads#create" # 其他路由配置... end
备选方案:猴子补丁(不推荐)
如果你不想创建新控制器,也可以通过猴子补丁直接修改原控制器的方法,但这种方式在Rails版本升级时可能出现兼容性问题,仅在特殊场景下使用:
# 在config/initializers/active_storage_custom_headers.rb中添加 ActiveStorage::DirectUploadsController.class_eval do private def direct_upload_json(blob) default_headers = blob.service_headers_for_direct_upload custom_headers = default_headers.merge( "Authorization" => "Bearer #{get_auth_token}", "X-Your-Custom-Header" => "your-custom-value" ) blob.as_json(root: false, methods: :signed_id).merge( direct_upload: { url: blob.service_url_for_direct_upload, headers: custom_headers } ) end def get_auth_token # 你的token获取逻辑 current_user&.auth_token end end
关键说明
direct_upload_json方法负责生成前端上传文件所需的配置,包括上传URL和请求头。我们在这里添加的自定义头会被前端用于后续的文件上传请求,确保存储服务能验证身份或接收自定义信息。- 请根据你的实际业务场景调整
get_auth_token方法,比如从当前用户会话、请求参数或自定义请求头中获取token。
内容的提问来源于stack exchange,提问作者belgoros
相关产品推荐
相关产品推荐

