socket發送http請求


socket發送http請求


 代碼示例(僅供參考):

(請注意,函數中以請求成功返回200為例,實際使用時需要判斷是否返回的是200)

/**
 * [socket_requst 使用socket發送請求]
 * @param  string $req_url    [請求地址]
 * @param  string $req_method [請求方式]
 * @param  array  $req_param  [請求參數]
 * @return [string | array]   [返回結果]
 */
function socket_requst($req_url='',$req_method='GET',$req_param=array()){
    if(empty($req_url)){
        return '請求的url不能為空';
    }
    $url_info = parse_url($req_url);
    //判斷端口
    $port = empty($url_info['port'])?80:$url_info['port'];
    //主機地址
    $host = $url_info['host'];
    //接口方法地址
    $path_url = $req_url;
    if(!empty($url_info['path'])){
        $parse_url = $url_info['path'];
    }
    
    //請求參數
    $data = '';
    if(is_array($req_param) && !empty($req_param)){
        $data = http_build_query($req_param);
    }
    //構建請求信息
    $out = $req_method ." " . $path_url . " HTTP/1.1\r\n";
    $out .= "Host: " .$host. "\r\n";
    $out .= "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36\r\n";
    $out .= "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
    $out .= "Referer: ".$req_url."\r\n";
    $out .= "Cookie: PHPSESSID=j1jhl5icqtfk8k7fc6j2c7fa93\r\n";
    $out .= "Content-Length: ".strlen($data) ."\r\n";
    $out .= "Connection: close\r\n\r\n";
    $out .= $data;
    //注意,頭部和參數之間要有兩個換行,用來區分。

    //判斷請求協議
    $protocol = substr($req_url,0,strpos($req_url,':'));
    if($protocol == 'http'){
        $req_prefix = '';//如果是http,可以寫'tcp://',也可以不寫
    }else if($protocol == 'https'){
        $req_prefix = 'ssl://';
    }else{
        $req_prefix = $protocol;
    }
    //打開網絡連接
    //參數:$hostname,int $port, &$errno,&$errstr,$timeout
    $fp = fsockopen($req_prefix . $host,$port,$errno,$errstr,5);

    if (!$fp) {
        echo "$errstr ($errno)<br />\n";
    }else{
        fwrite($fp,$out);
        $response = array('header'=>array(),'data'=>array());
        $is_header = true;

        $is_chunked = false;
        $is_json = false;
        while(!feof($fp)){
            $line_data = fgets($fp,1024);
            $replace_line_data = str_replace(array("\r\n", "\r", "\n"), "", $line_data);
            if($replace_line_data === ''){
                //響應頭和響應內容是以空行分割的
                //從這里之后是響應數據
                $is_header = false;
            }else{
                if($is_header){
                    $response['header'][] = $replace_line_data;
                    //判斷數據返回的形式
                    if($replace_line_data == 'Transfer-Encoding: chunked'){
                        //表明是以塊的形式返回的數據
                        $is_chunked = true;
                    }
                    //判斷是不是json
                    $tmp_arr = explode(' ',$replace_line_data);
                    if($tmp_arr[0] == 'Content-Type:'){
                        if($tmp_arr[1] == 'application/json;'){
                            $is_json = true;
                        }
                    }
                }else{
                    $response['data'][] = $replace_line_data; 
                }
            }
        }
        if($is_chunked){
            //如果是以快的形式返回,數據的是三部分的
            //第一部分:數據長度\r\n
            //第二部分:數據內容
            //第三部分:結束標識0\r\n\r\n
            //所以取第二部分
            $response['data'] = $response['data'][1];
        }else{
            $response['data'] = $response['data'][0];
        }
        if($is_json){
            //如果是json,返回數組形式
            $json_Arr = json_decode($response['data'],true);
            if(json_last_error() == 0){
                //正確的數據
                $response['data'] = $json_Arr;
            }else if(json_last_error() == 4){
                $correct_json_str = trim($response['data'], "\xEF\xBB\xBF");
                $json_Arr = json_decode($correct_json_str,true);
                $response['data'] = $json_Arr;                
            }
        }
        fclose($fp);
        return $response;
    }
}

調用示例:

$post_data = array('name'=>'zhang san','age'=>15);
$req_url = "https://www.test.com/Api/test";
$res = socket_requst($req_url,'POST',$post_data);

var_dump($res['header']);

var_dump($res['data']);

這個函數還不完善,僅供參考。

總結:

  1、用到了socket和文件操作的一些函數,如:fsockopen()、fwrite()、feof()、fgets()、fclose()。

  2、請求返回的數據形式不統一,當響應頭里有Transfer-Encoding: chunked時,返回的數據時以塊的形式返回的。

     如果是以塊的形式返回,數據的是三部分的:第一部分:數據長度\r\n,第二部分:數據內容,第三部分:結束標識0\r\n\r\n。

     在寫這個函數時,這里耗費了好長時間,發現數據不正常。

     參考【簡書】的猛猛的小盆友的文章 《如何使用socket進行Http請求和解析響應》。

     參考博客 放在垃圾桶里 的文章 《socket客戶端怎么判斷http響應數據的結束》。

  3、本來要返回字符串數據的,但解析數據時,發現json數據解析失敗,json_last_error=4,這個以前遇到過,為了避免大家這里踩坑,直接寫在了函數里。

  4、請求的協議,如果是http,可以寫'tcp://',也可以不寫,如果是https,寫'ssl://',其他的協議有udp://等。

  5、在構建請求頭時,冒號后要加一個空格,例如Host: 主機名,每個請求頭信息結束要換行,請求的參數要和頭信息隔兩行。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM