文档章节

PHP利用curl发起Http请求的400错误分析

jieqiuming
 jieqiuming
发布于 2016/11/05 23:52
字数 1602
阅读 1656
收藏 3

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

背景

现象一-php封装的http请求接口调用url

php的curl_exec接口调用结果.png

1.response的rawheader值显示400错误

HTTP/1.1 400 Unknown Version
Server: Tengine/2.0.3
Date: Tue, 19 Jul 2016 07:38:15 GMT
Content-Length: 0
Connection: keep-alive

2.自己封装的发送http请求接口

/**
* 发送httpful get请求
* @param  [array] $params [description]
* @return [object]         [description]
*/
public  function sendGetRequest($serverUrl,$params){
    try{
        $str_params = '';
        foreach ($params as $key => $value) {
            $str_params .= "&$key=".$value;
        }
        
        $response =  \Httpful\Request::get($serverUrl.$str_params)->send();
        return  $response->body;
    }catch(Execption $e){
        return array("statuscode"=>'-1',"message"=>'服务器出错了');
    }
    
}      

3.Request.php封装的Request对象的send方法

nategood/httpful中的Request::send方法使用php的curl_exec接口发起http请求。

/**
* Actually send off the request, and parse the response
* @return string|associative array of parsed results
* @throws ConnectionErrorException when unable to parse or communicate w server
*/
public function send()
{
    if (!$this->hasBeenInitialized())
        $this->_curlPrep();

    $result = curl_exec($this->_ch);

    if ($result === false) {
        if ($curlErrorNumber = curl_errno($this->_ch)) {
            $curlErrorString = curl_error($this->_ch);
            $this->_error($curlErrorString);
            throw new ConnectionErrorException('Unable to connect: ' . $curlErrorNumber . ' ' . $curlErrorString);
        }

        $this->_error('Unable to connect.');
        throw new ConnectionErrorException('Unable to connect.');
    }

    $info = curl_getinfo($this->_ch);

    // Remove the "HTTP/1.x 200 Connection established" string and any other headers added by proxy
    $proxy_regex = "/HTTP\/1\.[01] 200 Connection established.*?\r\n\r\n/s";
    if ($this->hasProxy() && preg_match($proxy_regex, $result)) {
        $result = preg_replace($proxy_regex, '', $result);
    }

    $response = explode("\r\n\r\n", $result, 2 + $info['redirect_count']);

    $body = array_pop($response);
    $headers = array_pop($response);

    curl_close($this->_ch);

    return new Response($body, $headers, $this, $info);
}

4.curl_exec调用前url值

http://192.168.59.146/api?version=1.0&format=json&appkey=KtSNKxk3&access_token=changyanyun&method=pan.file.export&uid=3062000039000412278&fileId=3aaaa5c8-3eaa-4511-91e7-46831d418f10&fileIndex={"lifecycle":{"auditstatus":"0"},"general":{"source":"UGC","creator":"\u6559\u5e080523","uploader":"gsres_iflytek_f968bca78360d38abcbaf23a5a318b12","extension":"ppt","title":"Unit12 What did you do last weekdend\u8bfe\u65f64\uff081\uff09"},"properties":{"subject":["01"],"edition":["01"],"stage":["010001"],"book":["01010101-001"],"unit":["01"],"course":[""],"unit1":["01"],"unit2":[""],"unit3":[""],"phase":["03"],"type":["0100"],"rrtlevel1":["08"]}}

现象二-浏览器中直接访问url

浏览器直接访问url接口调用结果.png

http://192.168.59.146/api?version=1.0&format=json&appkey=KtSNKxk3&access_token=changyanyun&method=pan.file.export&uid=3062000039000412278&fileId=3aaaa5c8-3eaa-4511-91e7-46831d418f10&fileIndex={ %22lifecycle%22:{ %22auditstatus%22:%220%22},%22general%22:{ %22source%22:%22UGC%22,%22creator%22:%22\u6559\u5e080523%22,%22uploader%22:%22gsres_iflytek_f968bca78360d38abcbaf23a5a318b12%22,%22extension%22:%22ppt%22,%22title%22:%22Unit12%20What%20did%20you%20do%20last%20weekdend\u8bfe\u65f64\uff081\uff09%22},%22properties%22:{ %22subject%22:[%2201%22],%22edition%22:[%2201%22],%22stage%22:[%22010001%22],%22book%22:[%2201010101-001%22],%22unit%22:[%2202%22],%22course%22:[%22%22],%22unit1%22:[%2202%22],%22unit2%22:[%22%22],%22unit3%22:[%22%22],%22phase%22:[%2203%22],%22type%22:[%220100%22],%22rrtlevel1%22:[%2208%22]}}

原因分析

对比现象一和现象二中的url值,可以发现:

  1. fileIndex参数值为json字符串
  2. fileIndex参数值中的title属性值中的空格字符在现象二中被编码为%20,且双引号"被编码为%22,此操作为浏览器自动执行
  3. 将url中的空格进行编码后,curl_exec接口返回200

测试代码

<?php
// 创建一个新cURL资源
$ch = curl_init();

$url = 'http://192.168.59.146/api?version=1.0&format=json&appkey=KtSNKxk3&access_token=changyanyun&method=pan.file.export&uid=3062000039000412278&fileId=3aaaa5c8-3eaa-4511-91e7-46831d418f10&fileIndex={"lifecycle":{"auditstatus":"0"},"general":{"source":"UGC","creator":"\u6559\u5e080523","uploader":"gsres_iflytek_f968bca78360d38abcbaf23a5a318b12","extension":"ppt","title":"Unit12 What did you do last weekdend\u8bfe\u65f64\uff081\uff09"},"properties":{"subject":["01"],"edition":["01"],"stage":["010001"],"book":["01010101-001"],"unit":["01"],"course":[""],"unit1":["01"],"unit2":[""],"unit3":[""],"phase":["03"],"type":["0100"],"rrtlevel1":["08"]}}';

//对url中的空格进行转义
if(isset($_GET["urlencode"])){
	$url = str_replace(" ", '%20', $url);
}

var_dump("url");
var_dump($url);
// 设置URL和相应的选项
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);

// 抓取URL并把它传递给浏览器
$result = curl_exec($ch);
var_dump("result");
var_dump($result);
if ($result === false) {
	if ($curlErrorNumber = curl_errno($this->_ch)) {
		$curlErrorString = curl_error($this->_ch);
		$this->_error($curlErrorString);
		throw new ConnectionErrorException('Unable to connect: ' . $curlErrorNumber . ' ' . $curlErrorString);
	}

	$this->_error('Unable to connect.');
	throw new ConnectionErrorException('Unable to connect.');
}
var_dump("ch");
var_dump($ch);

$info = curl_getinfo($ch);
var_dump("info");
var_dump($info);
// Remove the "HTTP/1.x 200 Connection established" string and any other headers added by proxy
$proxy_regex = "/HTTP\/1\.[01] 200 Connection established.*?\r\n\r\n/s";
if (preg_match($proxy_regex, $result)) {
	$result = preg_replace($proxy_regex, '', $result);
}

$response = explode("\r\n\r\n", $result, 2 + $info['redirect_count']);
var_dump("response");
var_dump($response);

$body = array_pop($response);
var_dump("body");
var_dump($body);
$headers = array_pop($response);
var_dump("headers");
var_dump($headers);


// 关闭cURL资源,并且释放系统资源
curl_close($ch);
?>

百分号编码(即url编码)

一般来说,URL只能使用英文字母、阿拉伯数字和某些标点符号,不能使用其他文字和符号。阮一峰在他的博文中提到,网络标准RFC 1738做了硬性规定:

"...Only alphanumerics [0-9a-zA-Z], the special characters "$-.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL." <br>"只有字母和数字[0-9a-zA-Z]、一些特殊符号"$-.+!*'(),"[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。"

url编码是特定上下文的统一资源定位符 (URL)的编码机制,服务器解析http请求时如果遇到非标准字符,会对该非标准字符进行编码

总结

当http请求出现400错误时,一般是http请求无效(bad request),url参数编码格式不正确导致。而url是有一定格式要求的,一般只能使用英文字母、阿拉伯数字和一些特殊字符,其他字符如空格和双引号需要经过编码后才能用户url。

  • 在浏览器中直接访问时浏览器会自动进行编码处理
  • 但是在程序中直接调用时则需要事先对url进行编码,如php使用curl_exec调用时需要对空格等非法字符进行编码
  • 特别是针对url参数中包含json数据值需要多加注意。

本文同步在我的原创博客中。


广告时间

这两年最重要的感悟就是,不管工作怎样,都要好好对自己,特别是自己的身体;女友很体谅我整天对着电脑工作,让我能每天坚持吃一个苹果;最近还开了一家网店,淘宝店铺名称叫砀山水果经营店8,她家有个苹果园,每年10月份是苹果的收获季节,刚摘下的苹果新鲜可口,又甜又脆,而且价格实惠,现在是10斤35元包邮哦;如果大家读到这里,希望大家前往淘宝店铺看看,同时也希望大家能捧场^-^,在此先谢谢各位童鞋啦.

淘宝店铺二维码 enter image description here

© 著作权归作者所有

jieqiuming
粉丝 2
博文 10
码字总数 10704
作品 0
合肥
高级程序员
私信 提问
加载中

评论(5)

jieqiuming
jieqiuming 博主
刚刚给我家苹果制作了一个官方网站页面,介绍了苹果的快递和采摘信息,http://qmjie.sinaapp.com/apple/
jieqiuming
jieqiuming 博主

引用来自“邻里”的评论

本想支持下,结果不发重庆的货!
感谢感谢啊,重庆目前是发不了的,邮费太贵了,也担心苹果弄坏了。。。
邻里
邻里
本想支持下,结果不发重庆的货!
jieqiuming
jieqiuming 博主

引用来自“hell0cat”的评论

可以调用php内置函数 http_build_query 对数组编码成字符串。
刚去支持了一下你家的苹果.😄
噢 多谢指导和支持我家的苹果啊 👍
hell0cat
hell0cat
可以调用php内置函数 http_build_query 对数组编码成字符串。
刚去支持了一下你家的苹果.😄
Nginx流量拷贝模块—ngx_http_mirror_module分析

原文出处:https://blog.csdn.net/xhjcehust/article/details/77093074 本文适合对nginx比较感兴趣的同学阅读,需要具备一定的服务端编程知识。 一、背景 最近nginx官网公布了nginx1.13.4最新...

kuSorZ
2018/07/18
0
0
Lua Web快速开发指南(7) - 高效的接口调用 - httpc库

httpc库基于cf框架都内部实现的socket编写的http client库. httpc库内置SSL支持, 在不使用代理的情况下就可以请求第三方接口. httpc支持header、args、body、timeout请求设置, 完美支持各种h...

水果糖的小铺子
06/16
18
0
curl 或 file_get_contents 获取需要授权页面的方法

今天因工作需要,需要用 curl / filegetcontents 获取需要授权(Authorization)的页面内容,解决后写了这篇文章分享给大家。 php curl 扩展,能够在服务器端发起POST/GET请求,访问页面,并能...

蜗牛奔跑
2016/03/07
42
0
file_get_contents 错误的请求

我用 php 的 file_get_conten 获取地址返回信息,出现[function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.0 400 Bad request 这个错误信息, allow_url_fopen......

balabalala
2012/09/03
693
4
php中curl_multi函数集的用法

一、引言 这段时间比较忙,已经很久没有写博客了。今天我就来聊聊我关于curlmulti*函数集的使用心得,关于http请求的问题。 当我们用户php发起一个http请求的时候。我们会首先想到用什么?没...

林湾村龙猫
2016/11/28
39
0

没有更多内容

加载失败,请刷新页面

加载更多

是否有内置功能可以打印对象的所有当前属性和值?

所以我在这里寻找的是类似PHP的print_r函数。 这样一来,我可以通过查看问题对象的状态来调试脚本。 #1楼 可能值得一看- 是否有与Perl的Data :: Dumper等效的Python? 我的建议是 https://gi...

技术盛宴
14分钟前
5
0
直击面试,聊聊 GC 机制

前言 文章来源:https://studyidea.cn/ GC 中文直译垃圾回收,是一种回收内存空间避免内存泄漏的机制。当 JVM 内存紧张,通过执行 GC 有效回收内存,转而分配给新对象从而实现内存的再利用。 ...

程序通事
17分钟前
4
0
Mybatis where 1=1 和 标签

在mybatis中拼接查询语句,偶尔会出现where后面可能一个字段的值都没有,就导致所有条件无效,导致where没有存在的意义;但也有可能这些条件会存在。那解决这个问题的方法,最常见的就是: ...

观海562
19分钟前
4
0
git常用初始化设置

日志编辑工具 git config --global core.editor vim ssh访问 cd /home/weiguangyue/.sshssh-keygen -t rsa -C weiyue888999@126.com 提交者信息用户名 git config --global user.nam......

萧默
20分钟前
4
0
面试题-关于Java线程池一篇文章就够了

在Java面试中,线程池相关知识,虽不能说是必问提,但出现的频次也是非常高的。同时又鉴于公众号“程序新视界”的读者后台留言让写一篇关于Java线程池的文章,于是就有本篇内容,本篇将基于J...

程序新视界
24分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部