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

React Native多图上传时出现ActiveSupport::MessageVerifier::InvalidSignature错误

React Native Expo上传图片到Rails 7 API触发ActiveSupport::MessageVerifier::InvalidSignature错误

使用React Native Expo开发客户端,上传两张图片至部署在render.com的Rails 7.0.6 API时触发ActiveSupport::MessageVerifier::InvalidSignature错误,其他功能正常。以下是相关代码及错误信息:


客户端上传代码

const onSubmit = async (values) => {
    const formData = new FormData();
    formData.append("claim[category_id]", category);
    formData.append("claim[client_id]", client);
    formData.append("claim[location]", JSON.stringify(location));
    formData.append("claim[comment]", values.comment);
    formData.append("claim[forwarded]", "false");
    formData.append("claim[user_id]", user.id);
    for (let i = 0; i < images.length; i++) {
      formData.append("claim[images][]", images[i]);
    }
    if (
      values.category &&
      values.client &&
      values.location &&
      images.length === 2
    ) {
      const response = await axios.post(`${GENERAL_URL}/claims`, formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      });
      const { success, claims } = response.data;
      if (success) {
        dispatch(addClaim(claims));
        Alert.alert("CONFIRMATION", "The Claim has been submitted", [
          null,
          { text: "OK", onPress: () => navigation.navigate("Explore") },
        ]);
      } else {
        alert("Oops! something went wrong, please try again");
      }
    } else {
      alert("Please fill in all fields");
    }
};

服务器错误日志

Started POST "/api/v1/claims" for 172.71.146.145 at 2023-07-06 11:21:52 +0000
Processing by Api::V1::ClaimsController#create as JSON
Parameters: {"claim"=>{"images"=>["file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fclaimsapp-e6f181ad-9716-464f-b689-fa016d86a564/Camera/8368dd02-db36-4fac-a411-b221e2e59cbb.jpg", "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fclaimsapp-e6f181ad-9716-464f-b689-fa016d86a564/Camera/e23136d2-b43a-4797-a626-50d0f917b896.jpg"], "category_id"=>"1", "client_id"=>"2", "location"=>"{\"altitude\":-13.300000190734863,\"heading\":0,\"latitude\":40.3746823,\"longitude\":49.8341172,\"altitudeAccuracy\":5.68895149230957,\"speed\":0,\"accuracy\":22.576000213623047}", "comment"=>"Test", "forwarded"=>"false", "user_id"=>"1"}}

Completed 500 Internal Server Error in 290ms (ActiveRecord: 14.3ms | Allocations: 10572)
FATAL -- : [d8db3e20-d76c-4258-a7db-fb13428d4a2f]
ActiveSupport::MessageVerifier::InvalidSignature (ActiveSupport::MessageVerifier::InvalidSignature):
app/controllers/api/v1/claims_controller.rb:40:in `create'

Rails API创建方法

def create
  @api_v1_claim = Claim.new(api_v1_claim_params)

  if @api_v1_claim.save
    updated_claims = Claim.where(user_id: @api_v1_claim.user_id)
    render json: { success: true, claims: updated_claims, code: 2201 }
  else
    render json: @api_v1_claim.errors, status: :unprocessable_entity
  end
end

private

def api_v1_claim_params
  params.require(:claim).permit(:comment, :location, :forwarded, :user_id, :client_id, :category_id, images: [])
end

Claim模型

class Claim < ApplicationRecord
  belongs_to :user
  belongs_to :client
  belongs_to :category

  has_many_attached :images

  def image_urls
    if images.attached?
      images.map do |image|
        Rails.application.routes.url_helpers.url_for(image, only_path: true)
      end
    end
  end

end

ClaimSerializer

class ClaimSerializer < ActiveModel::Serializer
  include JSONAPI::Serializer
  attributes :id, :location, :comment, :forwarded, :category_id, :user_id, :client_id, :images, :image_urls
end

使用环境:Ruby 3.1.3p185、Rails 7.0.6、React Native Expo


问题原因分析

从错误日志可见,客户端上传的images参数是本地文件路径字符串(file:///...),而非实际文件二进制数据。Rails处理Active Storage附件时,会尝试验证路径签名,但这些本地路径未经过Rails签名处理,因此触发InvalidSignature错误。

同时,客户端手动设置Content-Type: multipart/form-data虽然格式正确,但FormData中未包含文件对象,导致Rails无法正确解析文件。

解决步骤

1. 修复客户端上传逻辑,传递正确的文件对象

在React Native Expo中,相机/相册获取的图片需转换为FormData可识别的文件对象,而非直接传递本地路径。假设images数组是Expo ImagePicker返回的对象,修改如下:

for (let i = 0; i < images.length; i++) {
  const image = images[i];
  const file = {
    uri: image.uri,
    type: image.type || 'image/jpeg',
    name: image.fileName || `image-${i}.jpg`
  };
  formData.append("claim[images][]", file);
}

2. 移除手动设置的Content-Type(推荐)

Axios发送FormData时会自动生成包含boundary的正确Content-Type,手动设置可能导致边界符丢失,引发解析错误。可删除以下代码:

// headers: {
//   "Content-Type": "multipart/form-data",
// },

3. 验证Rails配置正确性

  • 确认config/storage.yml配置了正确的存储服务(生产环境推荐使用云存储,如S3);
  • 检查config/application.rb中已启用Active Storage:
    require "active_storage/engine"
    
  • 确保已执行rails active_storage:install及数据库迁移。

4. 修复Serializer错误

当前ClaimSerializer直接序列化images(Active Storage附件对象)会导致错误,只需保留image_urls字段:

class ClaimSerializer < ActiveModel::Serializer
  include JSONAPI::Serializer
  attributes :id, :location, :comment, :forwarded, :category_id, :user_id, :client_id, :image_urls
end

内容的提问来源于stack exchange,提问作者Emmanuel Mhango

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 09:29:53