zoukankan      html  css  js  c++  java
  • 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
    ";
        $out .= "Host: " .$host. "
    ";
        $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
    ";
        $out .= "Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    ";
        $out .= "Referer: ".$req_url."
    ";
        $out .= "Cookie: PHPSESSID=j1jhl5icqtfk8k7fc6j2c7fa93
    ";
        $out .= "Content-Length: ".strlen($data) ."
    ";
        $out .= "Connection: close
    
    ";
        $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 />
    ";
        }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("
    ", "
    ", "
    "), "", $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){
                //如果是以快的形式返回,数据的是三部分的
                //第一部分:数据长度
    
                //第二部分:数据内容
                //第三部分:结束标识0
    
    
                //所以取第二部分
                $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'], "xEFxBBxBF");
                    $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时,返回的数据时以块的形式返回的。

         如果是以块的形式返回,数据的是三部分的:第一部分:数据长度 ,第二部分:数据内容,第三部分:结束标识0 。

         在写这个函数时,这里耗费了好长时间,发现数据不正常。

         参考【简书】的猛猛的小盆友的文章 《如何使用socket进行Http请求和解析响应》。

         参考博客 放在垃圾桶里 的文章 《socket客户端怎么判断http响应数据的结束》。

      3、本来要返回字符串数据的,但解析数据时,发现json数据解析失败,json_last_error=4,这个以前遇到过,为了避免大家这里踩坑,直接写在了函数里。

      4、请求的协议,如果是http,可以写'tcp://',也可以不写,如果是https,写'ssl://',其他的协议有udp://等。

      5、在构建请求头时,冒号后要加一个空格,例如Host: 主机名,每个请求头信息结束要换行,请求的参数要和头信息隔两行。


  • 相关阅读:
    kong插件Prometheus+grafana图形化展示
    FTP服务—三种登录类型的配置方法
    [Kong] basic-auth基本认证及ACL鉴权
    centos7 U盘安装及Raid划分的完整流程
    [Kong] key-auth实现对API请求的密钥认证
    修改gitlab默认的nginx
    gitlab配置邮箱服务
    gitlab部署及汉化
    kong配置upstream实现简单的负载均衡
    mybaties只能驼峰映射,怎么可能,虐渣渣。(springboot)
  • 原文地址:https://www.cnblogs.com/gyfluck/p/11399927.html
Copyright © 2011-2022 走看看