PayPal Express ActiveMerchant网关初始化失败求助:传签名仍报错
首先,我们来拆解你遇到的问题根源:
你传入的参数哈希是字符串键(比如"signature"),但ActiveMerchant的PayPalExpressGateway初始化逻辑里,是通过符号键(:signature)来读取参数的。这就导致即使你传了签名值,代码里options[:signature]依然是nil,触发了An API Certificate or API Signature is required...的错误。
为什么硬编码参数能正常工作?
因为你硬编码的哈希用的是Ruby符号键(:login、:signature),和初始化代码期望的键类型完全匹配,所以options[:signature]能正确获取到值,不会触发错误。
如何修复Java Map到Ruby哈希的转换?
你的convert_hash方法现在只是把Java Map的键直接转成Ruby字符串键,我们需要修改它,把Java字符串键转换成Ruby符号键。修改后的方法如下:
def self.convert_hash(map) map.each_with_object({}) do |(key, value), hsh| # 将Java字符串键转为Ruby符号 ruby_key = key.to_s.to_sym hsh[ruby_key] = value end end
或者更简洁的写法(效果一致):
def self.convert_hash(map) Hash[map.map { |k, v| [k.to_s.to_sym, v] }] end
验证修复效果
转换后,你可以打印哈希确认键类型:
converted_hash = convert_hash(java_map) puts converted_hash.inspect
输出应该类似:
{:login=>"********************", :password=>"***************", :signature=>"AVtrAKGQXoUNJFduUU0pn1dewq80AK9KYWenyFwYcduz8elS85B8T0Wc", :allow_guest_checkout=>true, :test=>true}
此时所有键都是符号类型,和初始化代码的要求匹配,options[:signature]就能正确读取到你传入的签名值,不会再触发错误。
再回顾初始化代码的逻辑
看你提供的初始化代码:
options = { :pem => pem_file, :signature => signature, :headers => headers || {} }.update(options) if options[:pem].blank? && options[:signature].blank? raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal" end
这里的默认options[:signature]是nil(因为signature方法在初始化时还没赋值),当你传入的哈希是字符串键时,update方法不会覆盖:signature这个符号键,所以options[:signature]依然是nil,触发了错误。而转换成符号键后,update会用你传入的:signature值覆盖默认的nil,条件判断就不成立了。
内容的提问来源于stack exchange,提问作者Richtopia

