【发布时间】:2021-01-03 20:58:50
【问题描述】:
我正在使用 Firebase Cloud Functions 和 Paypal 在我的应用中为司机设置付款流程。要发布的url是Firebase中实际云功能的url:
尝试发送 HTTP Post 请求时,它似乎不起作用。请参阅下面的 payoutRequest() 和 Response 代码:
payoutRequest()
let email = txtPayoutEmail.text!
let uid = self.uid!
// Prepare URL:
let url = URL(string: "https://us-central1-ryyde-sj.cloudfunctions.net/payout")
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object:
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Headers
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Your Token", forHTTPHeaderField: "Authorization")
request.setValue("no-cache", forHTTPHeaderField: "cache-control")
print("request = \(request)")
// HTTP Request Parameters which will be sent in HTTP Request Body:
let postString = "uid=\(uid)&email=\(email)"
print("postString = \(postString)")
// Set HTTP Request Body
request.httpBody = postString.data(using: String.Encoding.utf8)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error ) in
print("data: \(String(describing: data))")
print("response: \(String(describing: response))")
print("error: \(String(describing: error))")
if let response = response as? HTTPURLResponse {
// Read all HTTP Response Headers
print("All headers: \(response.allHeaderFields)")
// Read a specific HTTP Response Header by name
if #available(iOS 13.0, *) {
print("Specific header: \(response.value(forHTTPHeaderField: "Content-Type") ?? " header not found")")
} else {
// Fallback on earlier versions
}
}
// Check for Errors
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string: \(dataString)")
}
}
task.resume()
回应
request = https://us-central1-ryyde-sj.cloudfunctions.net/payout
postString = uid=kv8JRVBwAfS1tgD04lNeM9esVzI2&email=myiosapp@me.com
data: Optional(138 bytes)
response: Optional(<NSHTTPURLResponse: 0x6000037d1c20> { URL: https://us-central1-ryyde-sj.cloudfunctions.net/payout } { Status Code: 400, Headers {
"Content-Length" = (
138
);
"Content-Type" = (
"text/html; charset=utf-8"
);
Date = (
"Thu, 17 Sep 2020 01:00:50 GMT"
);
Server = (
"Google Frontend"
);
"alt-svc" = (
"h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-27=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
);
"content-security-policy" = (
"default-src 'none'"
);
"function-execution-id" = (
cmrwbktlroxl
);
"x-cloud-trace-context" = (
"a85aaacd578e60690581aa64ead13b23;o=1"
);
"x-content-type-options" = (
nosniff
);
"x-powered-by" = (
Express
);
} })
error: nil
All headers: [AnyHashable("content-security-policy"): default-src 'none',
AnyHashable("Date"): Thu, 17 Sep 2020 01:00:50 GMT, AnyHashable("alt-svc"): h3-Q050=":443";
ma=2592000,h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-
T050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443";
ma=2592000; v="46,43", AnyHashable("Content-Type"): text/html; charset=utf-8,
AnyHashable("Content-Length"): 138, AnyHashable("x-cloud-trace-context"):
a85aaacd578e60690581aa64ead13b23;o=1, AnyHashable("Server"): Google Frontend,
AnyHashable("x-powered-by"): Express, AnyHashable("x-content-type-options"): nosniff,
AnyHashable("function-execution-id"): cmrwbktlroxl]
Specific header: text/html; charset=utf-8
Response data string: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Bad Request</pre>
</body>
</html>
如果请求成功,它将显示在以下链接的 PayPal 沙盒的 PayPal 通知中,但不是。
PayPal developer notifications link
我在 PayPal HTTP 请求方面没有太多经验。
我已经做了与我在这里尝试做的相同的事情,但在 Android 中它运行良好,所以我知道这应该可以工作,除了发布请求(我尝试使用在线示例来匹配我为 Android 应用程序所拥有的)
编辑
更新的 payoutRequest():
** ** 中的代码是新代码
let email = txtPayoutEmail.text!
let uid = self.uid!
// Prepare URL:
let url = URL(string: "https://us-central1-ryyde-sj.cloudfunctions.net/payout")
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object:
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Headers
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Your Token", forHTTPHeaderField: "Authorization")
request.setValue("no-cache", forHTTPHeaderField: "cache-control")
print("request = \(request)")
// HTTP Request Parameters which will be sent in HTTP Request Body:
**let body = ["uid": uid, "email": email]**
print("body = \(body)")
// Set HTTP Request Body
**request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: [])**
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error ) in
print("data: \(String(describing: data))")
print("response: \(String(describing: response))")
print("error: \(String(describing: error))")
if let response = response as? HTTPURLResponse {
// Read all HTTP Response Headers
print("All headers: \(response.allHeaderFields)")
// Read a specific HTTP Response Header by name
if #available(iOS 13.0, *) {
print("Specific header: \(response.value(forHTTPHeaderField: "Content-Type") ?? " header not found")")
} else {
// Fallback on earlier versions
}
}
// Check for Errors
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string: \(dataString)")
}
}
task.resume()
回应:
request = https://us-central1-ryyde-sj.cloudfunctions.net/payout
body = ["uid": "kv8JRVBwAfS1tgD04lNeM9esVzI2", "email": "driver@ryyde.com"]
data: Optional(0 bytes)
response: Optional(<NSHTTPURLResponse: 0x600001f0d6a0> { URL: https://us-central1-ryyde-sj.cloudfunctions.net/payout } { Status Code: 200, Headers {
"Content-Length" = (
0
);
"Content-Type" = (
"text/html"
);
Date = (
"Thu, 17 Sep 2020 04:41:29 GMT"
);
Server = (
"Google Frontend"
);
"alt-svc" = (
"h3-29=\":443\"; ma=2592000,h3-27=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
);
"function-execution-id" = (
cmrwtq89fdsr
);
"x-cloud-trace-context" = (
"f3fe884ca8499e7a10c7081ce222876e;o=1"
);
"x-powered-by" = (
Express
);
} })
error: nil
All headers: [AnyHashable("Content-Length"): 0, AnyHashable("x-cloud-trace-context"): f3fe884ca8499e7a10c7081ce222876e;o=1, AnyHashable("Server"): Google Frontend, AnyHashable("x-powered-by"): Express, AnyHashable("function-execution-id"): cmrwtq89fdsr, AnyHashable("alt-svc"): h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43", AnyHashable("Date"): Thu, 17 Sep 2020 04:41:29 GMT, AnyHashable("Content-Type"): text/html]
Specific header: text/html
Response data string:
编辑 2
当我运行我的代码时,我会检查 firebase/functions 中的函数日志(从下往上读取 - 函数活动似乎没问题)
编辑 3 - Charles 会议结果
URL https://us-central1-ryyde-sj.cloudfunctions.net 状态发送 请求正文... 备注 事务在会话被清除之前开始, 在会话清除之前传输的正文内容尚未被 捕获响应代码 200 连接已建立协议 HTTP/1.1 TLS TLSv1.2 (TLS_AES_128_GCM_SHA256) 协议 TLSv1.2 会话 已恢复 是 密码套件 TLS_AES_128_GCM_SHA256 ALPN - 客户端 证书 - 服务器证书 - 扩展方法 CONNECT 保留 Alive No Content-Type 客户端地址 127.0.0.1:57209 远程 地址 us-central1-ryyde-sj.cloudfunctions.net/216.239.36.54:443 标签 - 连接 WebSockets - 时间大小请求 1.77 KB (1,817 字节)响应 1.35 KB(1,379 字节)
编辑 4 - Android 代码
private void payoutRequest() {
progress = new ProgressDialog(this);
progress.setTitle("Processing your payout ...");
progress.setMessage("Please Wait .....");
progress.setCancelable(false);
progress.show();
// HTTP Request ....
final OkHttpClient client = new OkHttpClient();
// in json - we need variables for the hardcoded uid and Email
JSONObject postData = new JSONObject();
try {
postData.put("uid", FirebaseAuth.getInstance().getCurrentUser().getUid());
postData.put("email", mPayoutEmail.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
// Request body ...
RequestBody body = RequestBody.create(MEDIA_TYPE, postData.toString());
// Build Request ...
final Request request = new Request.Builder()
.url("https://us-central1-ryyde-sj.cloudfunctions.net/payout")
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("cache-control", "no-cache")
.addHeader("Authorization", "Your Token")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// something went wrong right off the bat
progress.dismiss();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// response successful ....
// refers to response.status('200') or ('500')
int responseCode = response.code();
if (response.isSuccessful()) {
switch(responseCode) {
case 200:
Snackbar.make(findViewById(R.id.layout),
"Payout Successful!", Snackbar.LENGTH_LONG)
.show();
break;
case 500:
Snackbar.make(findViewById(R.id.layout),
"Error: no payout available", Snackbar
.LENGTH_LONG).show();
break;
default:
Snackbar.make(findViewById(R.id.layout),
"Error: couldn't complete the transaction",
Snackbar.LENGTH_LONG).show();
break;
}
} else {
Snackbar.make(findViewById(R.id.layout),
"Error: couldn't complete the transaction",
Snackbar.LENGTH_LONG).show();
}
progress.dismiss();
}
});
}
【问题讨论】:
-
我建议使用Charles Proxy 之类的东西来查看您的工作 Android 请求和非工作 iOS 请求之间的区别。
-
这是我没有遇到过的。它究竟是做什么的?它是否需要我的 android 代码并使其与 ios 代码兼容?
-
哈哈,不,很遗憾没有。它是一种工具,可让您查看和检查所有网络请求和响应。您可以捕获您的 Android 请求和 iOS 请求,查看它们的原始标头和帖子正文等,这将使您可以比较它们以了解您在 iOS 端的问题所在。我强烈建议您学习如何使用它——它对于调试 http 请求问题非常有用,并且被 iOS 和 Android 开发人员广泛使用。
-
我在 Charles Proxy 中运行了一个请求,并在 EDIT 3 中附加了结果。
标签: android ios paypal google-cloud-functions httprequest