【发布时间】:2021-09-17 13:21:51
【问题描述】:
环境:
- Ubuntu 18.04.5 LTS
- PHP 7.2.24-0ubuntu0.18.04.7
- 卷曲 7.58.0
一般行为: 我正在使用 php cUrl 与 json rest api 连接。其中,api 规范显示了登录过程。
成功时,api 返回 http 级别 200 和类似的成功 json 字符串
{
"token":"ey...RU",
"expiration":"2021-07-07T00:39:45"
}
如果失败(假密码等),它会返回 http 级别 401 和类似的 json 字符串
{
"type": "https://tools.ietf.org/html/rfc7235#section-3.1",
"title": "Unauthorized",
"status": 401,
"traceId": "00-009af152168b684da1a6a543d11a3357-63fd91f4be1fc443-00"
}
我基本上在How to curl via php 处克隆了解决方案,但没有更改它返回 411 并且没有正文。我尝试了不同的接受标头,但没有成功。我还尝试了内容长度标头,但无济于事。我终于确定了那些使用 bash curl 方法的人。
要点: 在成功案例和失败案例中都需要 json 字符串。实际上,这适用于命令行领域,但仅适用于具有正确凭据的 php curl 的情况。
api 中还有其他几个 msg,它们返回各种 http 级别的失败代码,使用 bash curl,返回 json 字符串 - php curl 不返回。
实际结果: 使用具有正确凭据的任一方法,都会收到成功的 json 字符串(给出令牌和过期时间,如上所示)。
如果凭据不正确,bash curl 返回失败的 json 字符串:
> curl -X POST "https://<api endpoint url>/api/Authenticate/login" \
-H "accept: text/plain" -H "Content-Type: application/json-patch+json" \
-d "{\"username\":\"valid_username\",\"password\":\"bogus_password\"}"
{"type":"https://tools.ietf.org/html/rfc7235#section-3.1",
"title":"Unauthorized",
"status":401,
"traceId":"00-a4edb6cfca5918499f1bfaa073206118-da71a7d85e582448-00"}
尝试使用 php curl 使用虚假凭据登录,但没有:
$curl = curl_init();
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl, CURLOPT_URL, '<the real json endpoint uri>);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_VERBOSE, true);
# curl_setopt($curl, CURLOPT_STDERR, $out);
$hdrs = ["accept: text/plain",
"Content-Type: application/json-patch+json"
];
curl_setopt($curl, CURLOPT_HTTPHEADER, $hdrs);
$params = ['username' => 'valid_username',
'password' => 'bogus password'
];
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params));
// json_encode sanitization omitted here for clarity
$output = curl_exec($curl);
$responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if("200" != $responseCode)
$responseCode .= " - " . curl_error($curl);
$info = curl_getinfo($curl);
curl_close($curl);
print("==========\n\n");
printf("output: %s \n", var_export($output, true));
printf("responseCode: %s \n", $responseCode);
printf("info: %s \n", print_r($info, true));
print("==========\n\n");
输出: 注意没有失败的json主体。
* Trying 2xx.xxx.xx.xx...
* TCP_NODELAY set
* Connected to <the real json endpoint uri> (2xx.xxx.xx.xx) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=*.<the real json endpoint uri>
* start date: Jun 22 15:31:01 2021 GMT
* expire date: Sep 20 15:31:00 2021 GMT
* subjectAltName: host "<the real json endpoint uri>" matched cert's "<the real json endpoint uri>"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
> POST /api/Authenticate/login HTTP/1.1
Host: <the real json endpoint uri>
accept: text/plain
Content-Type: application/json-patch+json
Content-Length: 73
* upload completely sent off: 73 out of 73 bytes
* The requested URL returned error: 401 Unauthorized
* stopped the pause stream!
* Closing connection 0
==========
output: false
responseCode: 401 - The requested URL returned error: 401 Unauthorized
info: Array
(
[url] => https://<the real json endpoint uri>
[content_type] =>
[http_code] => 401
[header_size] => 0
[request_size] => 237
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.625
[namelookup_time] => 0.060492
[connect_time] => 0.156226
[pretransfer_time] => 0.428025
[size_upload] => 73
[size_download] => 0
[speed_download] => 0
[speed_upload] => 116
[download_content_length] => -1
[upload_content_length] => 73
[starttransfer_time] => 0.624949
[redirect_time] => 0
[redirect_url] =>
[primary_ip] => 2xx.xxx.xx.xx
[certinfo] => Array
(
)
[primary_port] => 443
[local_ip] => 10.10.10.105
[local_port] => 42192
)
==========
问题: php curl如何获取并显示401情况下的失败json response/body?
【问题讨论】:
-
// json_encode sanitization omitted here for clarity这是一个巨大的危险信号,因为json_encode()输出应该需要no“清理”。 -
您将 CURLOPT_FAILONERROR 设置为 true,这意味着 cURL 将不再在状态码 >= 400 的响应中返回请求正文。
-
@CBroe - 谢谢,谢谢,谢谢!如果您做出评论回答,我会检查它是否被接受。你修好了,你值得称赞:)
-
@sammitch - 不,但返回码可以。