使用lambda通过Node.js进行iOS Receiptvalidation

我正在Swift中开发一个iOS应用程序,并尝试实现应用内购买的接收validation。 我无法弄清楚如何在Swift中实现这个function,所以我试着在看到Giulio Roggero的例子之后,让我的应用程序通过Node.js中的Lambda函数写入请求。 我的Swift代码如下所示:

let receiptPath = Bundle.main.appStoreReceiptURL?.path if FileManager.default.fileExists(atPath: receiptPath!){ var receiptData:NSData? do{ receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped) } catch{ print("ERROR: " + error.localizedDescription) } let receiptString = receiptData?.base64EncodedString(options: .endLineWithLineFeed) let invocationRequest = AWSLambdaInvokerInvocationRequest() invocationRequest?.functionName = "sendReceiptRequest" invocationRequest?.invocationType = AWSLambdaInvocationType.requestResponse invocationRequest?.payload = ["receipt-data" : receiptString!, "password" : SUBSCRIPTION_SECRET] let lambdaInvoker = AWSLambdaInvoker.default() lock() lambdaInvoker.invoke(invocationRequest!).continue(with: AWSExecutor.mainThread(), with: { (task:AWSTask!) -> AnyObject! in if task.error != nil { self.sendErrorPopup("Error: \(task.error?.localizedDescription)") } else { print("TOKEN: ", task.result) } self.unlock() return nil })} 

下面的示例中,我的Lambda node.js函数如下所示:

 function (receiptData_base64, password, production, cb) { var url = production ? 'buy.itunes.apple.com' : 'sandbox.itunes.apple.com' var receiptEnvelope = { "receipt-data": receiptData_base64, "password":password }; var receiptEnvelopeStr = JSON.stringify(receiptEnvelope); var options = { host: url, port: 443, path: '/verifyReceipt', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(receiptEnvelopeStr) } }; var req = https.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (chunk) { console.log("body: " + chunk); cb(true, chunk); }); res.on('error', function (error) { console.log("error: " + error); cb(false, error); }); }); req.write(receiptEnvelopeStr); req.end(); } 

但是,当运行这个代码时,无论是通过lambdatesting还是通过我的应用程序,我都会得到一个错误消息,简单的说Response body: {"errorMessage":"true"} 。 我注意到,如果我调整代码,我可以创build更多预期的错误 – 例如,如果我有一些其他价值的收据数据,我得到一个21002错误代码作出回应,如果我改变“生产”为真,我得到一个21007错误。 部分问题是我不知道callback应该如何工作 – https.request中的块https.request正确,我想在Swift中做什么? 我得到的印象是收据数据格式正确,因为改变它会产生不同的结果,为什么最终的结果仍然是一个错误?

编辑:

之前我没有注意到的是,当我运行Lambda函数时,会出现“body:(receipt data)”这一行,其中(接收数据)是我发送给函数的base 64编码数据。 这让我怀疑我没有到达错误callback模块,并且这个错误与我将callback的结果发送回我的应用程序的方式有关。 什么是这个块:

 var req = https.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (chunk) { console.log("body: " + chunk); cb(true, chunk); }); res.on('error', function (error) { console.log("error: " + error); cb(false, error); }); }); 

应该做的? 是否有可能我需要启用一些权限来接收callback?

最终,我通过遵循这个例子并使用Python而不是Node.js解决了这个问题。 我仍然不知道我的代码究竟出了什么问题,但是在Swift中使用base-64编码,然后将收据数据和密码发送到Python Lambda函数,这样给我的结果是正确的。

对于后来发现这个问题的人来说,

  1. 这里最大的问题是Content-Type不正确。 你需要发布JSON,而不是URL编码; 而代码是这样做的,它使用错误的types告诉服务器它使用的是什么格式。 它应该是application/json而不是application/x-www-form-urlencoded
  2. 发送给苹果服务器的Base64 不得 (至less在上周)包含行结尾。 我不知道这是一个问题,但是这是我以前碰到的, .endLineWithLineFeed让我怀疑。
  3. 该algorithm用于在服务器之间切换。 该方法应该尝试validation生产服务器的收据,而不是允许在生产和沙箱之间切换。 如果结果对象的status21007 ,则代码应该对沙盒服务器尝试相同的收据。 一旦收据被解码和validation,客户可以检查收据以查看哪个服务器被validation,并且(如有必要)忽略沙箱收据。

在你的Swift代码中,你检查“如果task.error!= nil”,那么你有一个错误

  lambdaInvoker.invoke(invocationRequest!).continue(with: AWSExecutor.mainThread(), with: { (task:AWSTask!) -> AnyObject! in if task.error != nil { self.sendErrorPopup("Error: \(task.error?.localizedDescription)") } else { print("TOKEN: ", task.result) } 

但是在你的节点代码中,你可以这样调用callback函数:

 cb(true, chunk); 

第一个参数是你的错误,不会是零。 你应该把这行代替:

 cb(null, chunk); 

你会这样得到你正确的Json