socket发送http请求
HTTP 请求 发送 socket
2023-09-11 14:22:41 时间
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: 主机名,每个请求头信息结束要换行,请求的参数要和头信息隔两行。
相关文章
- go http请求库HttpRequest
- PHP如何通过Http Post请求发送Json对象数据?
- 浅论Android网络请求库——android-async-http
- HTTP请求报文解剖
- Dart的HTTP请求和响应(1)
- android 发送http请求
- 通过http请求传递xml流和接收xml流的代码示例
- nginx重新整理——————http请求的11个阶段中的precontent阶段[十六]
- vscode插件:REST Client发送http请求
- golang http发送GET请求在认证时忽略证书校验
- 使用 http-proxy 代理 SAP UI5 应用发起的 HTTP 请求
- 关于 SAP Spartacus SSR 模式和 CSR 模式下重复发送 HTTP 请求调用 OCC API 的问题
- 使用jMeter构造大量并发HTTP请求进行微服务性能测试
- 如何使用jMeter发送两个逻辑上相关的HTTP请求
- Cordova内部http请求的proxy实现原理
- Atitit 返回http500返回码,以及自定义返回提示 目录 1. 可以看到从php发送http响应代码的三种方法:1 1.1. Header("HTTP/1.1 404 Not Found"
- Atitit 微服务实践 艾提拉著 微服务主要解决几个问题负载均很 目录 1. 微服务的模式 http请求层 vs服务层1 1.1. Http vs 服务层优缺点1 2. 实现技术2
- Spartacus payment types 在 checkout 步骤中发送 HTTP put 请求的实现明细
- 使用Angular reactive form发送HTTP请求的一个简单例子
- 云小课|使用SpringBoot快速构建FunctionGraph HTTP函数
- [手游项目4]-24-Linux下实现C语言的HTTP请求实现
- Servlet 客户端 HTTP 请求
- 使用Guzzle执行HTTP请求