http请求包含三个部分,请求行(\r\n)请求头(\r\n\r\n)请求主体
http相应包含三部分,状态行(\r\n)响应头(\r\n\r\n)响应主体
起始行与header之间通过一个换行符分隔(\r\n),多个header字段之间也是通过换行符分隔(\r\n),报文首部与报文主体之间则通过一个一个空行分隔(\r\n\r\n),报文首部有纯文本格式的字符串组成,报文主体则可以包含多种格式数据。
php的 fsockopen可以让我们自己构造请求header,获取响应header和响应主体数据
/**
* 使用fsockopen发送URL请求
* @param $url
* @param $method: GET、POST等
* @param array $params
* @param array $header
* @param int $timeout
* @return array|bool
*/
function sendHttpRequest($url, $method = 'GET', $params = [], $header = [], $timeout = 30)
{
$urlInfo = parse_url($url);
if (isset($urlInfo['scheme']) && strcasecmp($urlInfo['scheme'], 'https') === 0) //HTTPS
{
$prefix = 'ssl://';
$port = 443;
}else{ //HTTP
$prefix = 'tcp://';
$port = isset($urlInfo['port']) ? $urlInfo['port'] : 80;
}
$host = $urlInfo['host'];
$path = isset($urlInfo['path']) ? $urlInfo['path'] : '/';
if(!empty($params) && is_array($params))
{
$params = http_build_query($params);
}
$contentType = '';
$contentLength = '';
$requestBody = '';
if($method === 'GET')
{
$params = $params ? '?' . $params : '';
$path .= $params;
}else{
$requestBody = $params;
$contentType = "Content-Type: application/x-www-form-urlencoded\r\n";
$contentLength = "Content-Length: " . strlen($requestBody) . "\r\n";
}
$auth = '';
if(!empty($urlInfo['user']))
{
$auth = 'Authorization: Basic ' . base64_encode($urlInfo['user'] . ':' . $urlInfo['pass']) . "\r\n";
}
if($header && is_array($header))
{
$tmpString = '';
foreach ($header as $key => $value)
{
$tmpString .= $key . ': ' . $value . "\r\n";
}
$header = $tmpString;
}else{
$header = '';
}
$out = "$method $path HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= $auth;
$out .= $header;
$out .= $contentType;
$out .= $contentLength;
$out .= "Connection: Close\r\n\r\n";
$out .= $requestBody;//post发送数据前必须要有两个换行符\r\n
//返回一个句柄$fp
$fp = fsockopen($prefix . $host, $port, $errno, $errstr, $timeout);
if(!$fp)
{
return false;
}
//向$fp写入请求报文
if(!fwrite($fp, $out))
{
return false;
}
$response = '';
//读取$fp就是读取响应数据
while(!feof($fp))
{
$response .= fread($fp, 1024);
}
if(!$response)
{
return false;
}
fclose($fp);
$separator = '/\r\n\r\n|\n\n|\r\r/';
list($responseHeader, $responseBody) = preg_split($separator, $response, 2);
$httpResponse = array(
'header' => $responseHeader,
'body' => $responseBody
);
return $httpResponse;
}