今天在作一個小程序的API請求,發現直接經過微信小程序請求是能夠返回數據的,可是把數據發送給PHP,有cURL來請求就發生http請求出現400錯誤。檢查了老半天,沒發現錯誤而後就把cURL從新寫了一邊也仍是沒有生效。後面查找資料發現一篇文章說明這個問題,是請求參數編碼格式不正確致使的,漢字須要轉碼成URL編碼,才能正常訪問。下面是這篇文章的內容。php
摘要: 當http請求出現400錯誤時,通常是http請求無效(bad request),url參數編碼格式不正確致使。而url是有必定格式要求的,通常只能使用英文字母、阿拉伯數字和一些特殊字符,其餘字符如空格和雙引號須要通過編碼後才能用戶url。 1.在瀏覽器中直接訪問時瀏覽器會自動進行編碼處理 2.可是在程序中直接調用時則須要事先對url進行編碼,如php使用curl_exec調用時須要對空格等非法字符進行編碼。 3.特別是針對url參數中包含json數據值須要多加註意。html
背景json
現象一-php封裝的http請求接口調用url小程序
1.response的rawheader值顯示400錯誤微信小程序
1api |
HTTP/1.1 400 Unknown VersionServer: Tengine/2.0.3Date: Tue, 19 Jul 2016 07:38:15 GMTContent-Length: 0Connection: keep-alive 瀏覽器 |
2.本身封裝的發送http請求接口服務器
1微信 2網絡 3 4 5 6 7 8 9 10 11 12 |
/** * 發送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請求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/** * 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值
1 |
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
1 |
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值,能夠發現:
fileIndex參數值爲json字符串
fileIndex參數值中的title屬性值中的空格字符在現象二中被編碼爲%20,且雙引號"被編碼爲%22,此操做爲瀏覽器自動執行
將url中的空格進行編碼後,curl_exec接口返回200
測試代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<!--?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."
"只有字母和數字[0-9a-zA-Z]、一些特殊符號"$-.+!*'(),"[不包括雙引號]、以及某些保留字,才能夠不通過編碼直接用於URL。"
url編碼是特定上下文的統一資源定位符 (URL)的編碼機制,服務器解析http請求時若是遇到非標準字符,會對該非標準字符進行編碼
總結
當http請求出現400錯誤時,通常是http請求無效(bad request),url參數編碼格式不正確致使。而url是有必定格式要求的,通常只能使用英文字母、阿拉伯數字和一些特殊字符,其餘字符如空格和雙引號須要通過編碼後才能用戶url。
在瀏覽器中直接訪問時瀏覽器會自動進行編碼處理
可是在程序中直接調用時則須要事先對url進行編碼,如php使用curl_exec調用時須要對空格等非法字符進行編碼。
特別是針對url參數中包含json數據值須要多加註意。
轉載源地址:http://www.php.cn/php-ercikaifa-338598.html