php curl返回400 bad request的问题定位与解决

oops 今晚花了整整一晚的时间帮同事定位一个php curl返回400 bad request的问题了,@七夕Orz.. 是一个网上流传的模拟登陆163邮箱、获取通信录的代码段google,在同事和我的开发机上都运行正常,但是部署到服务器环境上就400了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//跳转
$url = 'http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight=1&verifycookie=1&language=-1&style=-1&username=loki_wuxi';
$headers = array('User-Agent' =>
'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/2008052906 Firefox/3.0');

$ch = curl_init($url);
curl\_setopt($ch, CURLOPT\_RETURNTRANSFER, true);
curl\_setopt($ch, CURLOPT\_HEADER, true);
curl\_setopt($ch, CURLOPT\_CONNECTTIMEOUT, 120);
curl\_setopt($ch, CURLOPT\_POST, true);
curl\_setopt($ch, CURLOPT\_HTTPHEADER, $headers);
curl\_setopt($ch, CURLOPT\_COOKIEFILE, COOKIEJAR);
curl\_setopt($ch, CURLOPT\_COOKIEJAR, COOKIEJAR);
$result = curl_exec($ch);
curl_close($ch);

由于两个开发环境都是windows,服务器环境是linux,所以至少花了一个小时走弯路,在COOKIEJAR文件的路径和权限上。未果 病急乱投医的试遍了网上的各种方案,最后还是沉下心来分析http header,php curl输出完整的request header,需要如下设置

1
2
3
4
5
6
7
$ch = curl_init($url);
curl\_setopt($ch, CURLOPT\_HEADER, true);
curl\_setopt($ch, CURLINFO\_HEADER_OUT, true);
curl\_setopt($ch, CURLOPT\_NOBODY, true);
$result = curl_exec($ch);
print\_r(curl\_getinfo($ch));
curl_close($ch);

对比本机和生产环境的request_header,发现主要区别在于

1
2
本机的  Content-Length: 0 Content-Type: application/x-www-form-urlencoded
服务器 Content-Length: -1 Content-Type: application/x-www-form-urlencoded Expect: 100-continue

最终根据这个线索在StackoverFlow上找到这篇Testing PHP CURL file uploads on laptop (blocked by Norton)

It looks like I had curl_setopt($CURL, CURLOPT_POST, TRUE), and that wasn’t a good idea. I removed it, and Norton doesn’t complain and the script works.

把下面这行注释了就ok了,确实在没有CURLOPT_POSTFIELDS的情况下post内容为空,开启CURLOPT_POST没有意义

1
//curl\_setopt($ch, CURLOPT\_POST, true);

但是,还是要纠结一下,为什么在本机测试ok了,是不是windows和linux环境的却别?刨根问底的继续查了下,终于找到问题的根源,原来是curl的版本不一样,我本机是libcurl/7.16.0,服务器上是libcurl/7.27.0 详细解释参见 http://sevalapsha.wordpress.com/2011/08/03/curl-http11-empty-post-bug/

In the end we discovered that newer version (since 7.20) of cURL interprets missing body as a negotiation request – sends Expect: 100-continue header and Content-Length: -1.

curl官方的log http://curl.haxx.se/changes.html#7_20_0

Fixed in 7.20.0 - February 9 2010
Changes:
send Expect: 100-continue for POSTs with unknown sizes

总结一下,就是这些.. (声明下,这篇文章的除了最初同事的代码片之外,所有的引用都是英文,其中一篇还需要自备梯子才能看,这里不是得瑟什么,就是这么个情况,解决问题的有效渠道就是google groups和stackoverflow) 洗洗睡了,某娜快回来了,希望明年七夕不要再解bug.. T-T 本文地址:http://awebird.com/blog/art/99

原wordpress评论