尴尬的 curl 和尴尬的我

2024/12/24 计算机网络

事情的起因是这样的,对接某个接口,一个POST请求的请求体比较大(注:跟系统和curl的版本有关,有的并不会发送Except请求头),curl默认给我发送了Expect请求头,事前我并不知道,但一直没调通,对方就提出要看看我的HTTP报文。

糟糕,你让我手写一个HTTP请求报文,我分分钟就能写出来,不就这么简单么:

POST /xxx HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 12

name=lwlinux

你让我获取curl的请求报文,突然就觉得有点懵,我还真找不到直接的接口来获取,不管是curl命令还是使用了curl库的php,它都没有。只能采取折中的办法,curl有个-v选项,但--trace-ascii curl.trace.log保存到文件中显然更适合处理,换成php中的curl,则对应以下代码:

<?php

$verboseFile = __DIR__. '/curl.trace.log';
$verboseFd = fopen($verboseFile, 'w+');

curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $verboseFd);

一个完整的示例代码如下:

<?php

$url = 'http://nginx/programming_practice/php/snippets/php.php';
$body = http_build_query(['name' => str_repeat('lwlinux', 200)]);

$verboseFile = __DIR__. '/curl.trace.log';
$verboseFd = fopen($verboseFile, 'w+');

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $verboseFd);

$resp = curl_exec($ch);
$respInfo = curl_getinfo($ch);
$curlError = curl_error($ch);
$curlErrno = curl_errno($ch);

curl_close($ch);
fclose($verboseFd);

var_dump(
    'verbose   ==============================================',
    file_get_contents($verboseFile),
    'request   ==============================================',
    $body,
    'response  ==============================================',
    $resp,
    'respInfo  ==============================================',
    $respInfo,
    'curlError ==============================================',
    $curlError,
    'curlErrno ==============================================',
    $curlErrno
);

以上代码输出片段如下,忽略一些多余的内容,应该大概能看懂吧。

* Expire in 0 ms for 6 (transfer 0x400160b760)
* Expire in 1 ms for 1 (transfer 0x400160b760)
* Expire in 0 ms for 1 (transfer 0x400160b760)
* Expire in 1 ms for 1 (transfer 0x400160b760)
*   Trying 172.18.0.6...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x400160b760)
* Connected to nginx (172.18.0.6) port 80 (#0)
> POST /programming_practice/php/snippets/php.php HTTP/1.1
Host: nginx
Accept: */*
Content-Length: 1027
Content-Type: application/x-www-form-urlencoded
Expect: 100-continue

* Expire in 1000 ms for 0 (transfer 0x400160b760)
< HTTP/1.1 100 Continue
* We are completely uploaded and fine
< HTTP/1.1 200 OK
< Server: nginx/1.19.2
< Date: Wed, 25 Dec 2024 01:30:42 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP/7.4.10
< 
* Connection #0 to host nginx left intact

看到了吧,POST /programming_practice/php/snippets/php.php HTTP/1.1之后就是完整的请求头,只需要字符串操作一下就可以获取。当然curl命令的-v参数输出的样式看起来会相对舒服。记住,不是所有curl命令都会发送Expect请求头,这个是由curl版本和系统决定的。

有没有Expect不是重点,重点是学会怎么查看curl的请求报文,这样对于调试接口会有很大的帮助。

curl虽说方便,但也有用着不舒服的地方;php也是,获取原始请求报文和响应报文这方面,确实令人不愉快。

Search

    Table of Contents