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

oops

今晚花了整整一晚的时间帮同事定位一个php curl返回400 bad request的问题了,@七夕Orz..

是一个网上流传的模拟登陆163邮箱、获取通信录的代码段google,在同事和我的开发机上都运行正常,但是部署到服务器环境上就400了

//跳转
			$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,需要如下设置

$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,发现主要区别在于

本机的  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没有意义

//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

php curl返回400 bad request的问题定位与解决》上有2条评论

  1. 且听风吟

    非常感谢,我也是在本地可以,放到服务器上就不行。在网上找了很久没找到原因,也找到了stackoverflow,但是看不懂。按照你说的注释掉curl_setopt($ch, CURLOPT_POST, true);就解决了。
    以前记得放的是windows的服务器没问题,后来迁到linux的就出有这问题了。希望遇到这问题的小伙伴可以在这个站找到解决办法。
    谢谢楼主。

    回复
  2. gaydon

    遇到一毛一样的问题,别人写的代码放在window跑正常,放到linux服务器跑400错误。大概也是curl版本不同,完美解决了我的问题。

    回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注