mturk API给出了;指定的索赔无效”;大约一半的时间发送消息;重新提交随机修复


mturk API gives "specified claims are invalid" message about half the time; resubmitting randomly fixes

我使用自定义PHP脚本,根据PHP-AWS库中的签名函数向mturk API提交请求。下面是一个请求示例:

https://mechanicalturk.amazonaws.com/?Service=AWSMechanicalTurkRequester&AWSAccessKeyId=MYKEY&Version=2012-03-25&Operation=NotifyWorkers&Signature=j+4UTX9x3EKltvWpoxIkp4BM6S4=&Timestamp=2015-06-25T09:37:51Z&Subject=test&MessageText=just+testing+&WorkerId.1=SOMEID

有时一个给定的脚本会工作,而在其他时候,同一个脚本会返回这样的错误:

AWS.BadClaimsSupplied The specified claims are invalid. Based on your request, your signature should be generated using the following string: AWSMechanicalTurkRequesterNotifyWorkers2015-06-25T09:37:51Z. Check to make sure your system clock and timezone is not incorrect. Our current system time: 2015-06-25T09:37:51Z. (1435225071849)

当我得到AWS.BadClaimsSupplied错误时,反复重新运行脚本将导致它最终工作。所谓"工作",我的意思是API返回true并执行所需的操作,或者返回与我请求的操作相关的错误。

我认为,如果我错误地执行了哈希或使用了错误的签名,那么它将永远不会工作*。问题的间歇性使我认为这是一个时间错误。但上面的例子显示了一条错误消息,其中我用于签名的时间与他们的时间相同,所以这似乎也不是问题所在。

*好吧,它会在每2^160次尝试中工作一次。

我试着把我的时间戳倒计时1秒,以防我领先一点;这并没有改变结果。我想不出任何其他方法来调试它。

错误消息听起来问题出在被散列的字符串上,但实际问题是一些散列的字符串包含特殊字符。字符+/=会影响URL的解析方式,并会干扰签名的读取。使用不同的时间字符串重新运行请求将随机返回一个没有这些字符的哈希,从而允许请求工作。

解决方案:在进行API调用之前,只需对签名运行urlencode()。如果出于某种原因你不想这样做,这个答案提供了一些只编码这些特定字符的代码,但我认为标准函数更全面、更安全。