各位技术大牛们,大家好!我是今天的主讲人,很高兴能在这里和大家一起深入研究 WordPress 核心函数 wp_remote_get()
的源码。今天咱们就来扒一扒它的皮,看看它到底是如何处理远程 HTTP 请求的,让大家对它有一个更加清晰和深入的了解。
开场白:HTTP,你好!
在Web开发的世界里,HTTP协议就像一位默默奉献的邮递员,负责在客户端(比如我们的浏览器)和服务器之间传递信息。而wp_remote_get()
函数,就是WordPress世界里的一位熟练的邮递员,专门负责向远程服务器发出“取件”请求(GET请求),然后把取回来的“包裹”(HTTP响应)交给我们处理。
正文:解剖 wp_remote_get()
wp_remote_get()
函数实际上是 wp_remote_request()
函数的一个简化版本,它专门用于发送 GET 请求。wp_remote_request()
函数才是真正的幕后英雄,负责处理各种 HTTP 请求(GET, POST, PUT, DELETE等)。所以,要彻底了解 wp_remote_get()
,我们必须先从 wp_remote_request()
入手。
1. wp_remote_request()
:请求的起点
wp_remote_request()
函数的原型如下:
function wp_remote_request( $url, $args = array() ) {
global $wp_version;
$defaults = array(
'method' => 'GET',
'timeout' => 5,
'redirection' => 5,
'httpversion' => '1.0',
'user-agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' ),
'reject_unsafe_urls' => true,
'blocking' => true,
'headers' => array(),
'body' => null,
'cookies' => array(),
'filename' => null,
'stream' => false, // Add support for streaming response body
'sslverify' => true, // Verify SSL certificates
'sslcertificates' => false, // Set custom SSL certificates path
'compress' => false, // Should we compress the body?
'decompress' => true, // Should we auto-decompress the response?
'limit_response_size' => null // Maximum response body size to download
);
$args = wp_parse_args( $args, $defaults );
//... (更多代码)
}
$url
: 这是我们要请求的远程 URL,邮递员要去的地址。$args
: 这是一个数组,包含了各种请求参数,比如请求方法、超时时间、HTTP版本、用户代理等等。
重点参数解析:
参数名 | 描述 | 默认值 |
---|---|---|
method |
HTTP 请求方法(GET, POST, PUT, DELETE 等)。 | GET |
timeout |
请求超时时间,单位是秒。如果超过这个时间没有收到响应,就会返回一个错误。 | 5 |
redirection |
最大重定向次数。如果服务器返回重定向响应(比如 301, 302),wp_remote_request() 会自动重定向,直到达到这个最大次数为止。 |
5 |
httpversion |
使用的 HTTP 协议版本(1.0 或 1.1)。 | 1.0 |
user-agent |
User-Agent 头部,用来标识请求的客户端。WordPress 默认会设置为 WordPress/版本号; 站点URL 。 |
WordPress/版本号; 站点URL |
blocking |
是否阻塞请求。如果设置为 true ,函数会一直等待直到收到响应才返回。如果设置为 false ,函数会立即返回,请求会在后台执行。 |
true |
headers |
一个关联数组,包含了要发送的 HTTP 头部。 | array() |
body |
请求体,用于 POST, PUT 等请求。 | null |
cookies |
一个数组,包含了要发送的 cookies。 | array() |
filename |
如果要将响应保存到文件中,可以指定文件名。 | null |
stream |
是否流式传输响应体。如果设置为 true ,响应体将以流的方式读取,而不是一次性加载到内存中。这对于处理大型响应非常有用。 |
false |
sslverify |
是否验证 SSL 证书。强烈建议设置为 true ,以确保连接的安全性。 |
true |
sslcertificates |
自定义SSL证书路径。 | false |
compress |
是否对请求体进行压缩。 | false |
decompress |
是否自动解压缩响应体。 | true |
limit_response_size |
限制下载响应体的大小。 | null |
2. 选择合适的传输方式
wp_remote_request()
函数会根据当前环境选择合适的 HTTP 传输方式。它会依次尝试以下几种方式:
- Streams: 如果 PHP 启用了
allow_url_fopen
,并且 URL 是 HTTP 或 HTTPS,那么会使用 PHP 的流函数来处理请求。 - cURL: 如果 PHP 启用了 cURL 扩展,那么会使用 cURL 来处理请求。这是最常用和推荐的方式,因为它功能强大且稳定。
- Fsockopen: 如果以上两种方式都不可用,那么会使用
fsockopen()
函数来建立 socket 连接,手动发送 HTTP 请求。
// Determine which transport to use.
$transports = array( 'streams', 'curl', 'fsockopen' );
// Filter the transports array.
$transports = apply_filters( 'http_api_transports', $transports, $url, $args );
// Find a suitable transport.
$response = false;
foreach ( $transports as $transport ) {
$class = 'WP_HTTP_' . ucfirst( $transport );
if ( ! class_exists( $class ) ) {
continue;
}
$http = new $class();
if ( ! $http->test( $url ) ) {
continue;
}
$response = $http->request( $url, $args );
if ( ! is_wp_error( $response ) ) {
break;
}
}
这段代码会遍历 transports
数组,依次尝试每种传输方式。如果某种方式可用并且成功发送了请求,那么就跳出循环,不再尝试其他方式。
3. 使用 Streams (WP_HTTP_Streams)
如果选择了 Streams 方式,WP_HTTP_Streams
类会使用 PHP 的流函数来处理请求。
class WP_HTTP_Streams {
public function request( $url, $args = array() ) {
//...
$stream_options = array(
'http' => array(
'method' => $method,
'user_agent' => $args['user-agent'],
'max_redirects' => $args['redirection'],
'timeout' => $args['timeout'],
'ignore_errors' => true, // Return content even on errors
'protocol_version' => $args['httpversion'],
'header' => $headers,
'content' => $body,
),
'ssl' => array(
'verify_peer' => $args['sslverify'],
'verify_peer_name' => $args['sslverify'],
),
);
$context = stream_context_create( $stream_options );
$stream = @fopen( $url, 'r', false, $context );
if ( ! $stream ) {
return new WP_Error( 'http_request_failed', __( 'Failed to open stream' ) );
}
$response = stream_get_contents( $stream );
$meta = stream_get_meta_data( $stream );
fclose( $stream );
//...
}
}
这段代码会创建一个 stream context,包含了请求的各种参数,然后使用 fopen()
函数打开 URL,读取响应内容。
4. 使用 cURL (WP_HTTP_Curl)
如果选择了 cURL 方式,WP_HTTP_Curl
类会使用 cURL 扩展来处理请求。
class WP_HTTP_Curl {
public function request( $url, $args = array() ) {
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_HEADER, true );
curl_setopt( $ch, CURLOPT_USERAGENT, $args['user-agent'] );
curl_setopt( $ch, CURLOPT_TIMEOUT, $args['timeout'] );
curl_setopt( $ch, CURLOPT_MAXREDIRS, $args['redirection'] );
curl_setopt( $ch, CURLOPT_HTTP_VERSION, ($args['httpversion'] == '1.1') ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0 );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, $args['sslverify'] );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, $args['sslverify'] ? 2 : 0 );
if ( 'POST' == $method || 'PUT' == $method ) {
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $args['body'] );
}
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
$response = curl_exec( $ch );
if ( false === $response ) {
$error_message = curl_error( $ch );
$error_code = curl_errno( $ch );
curl_close( $ch );
return new WP_Error( 'http_request_failed', $error_message, $error_code );
}
$header_size = curl_getinfo( $ch, CURLINFO_HEADER_SIZE );
$header = substr( $response, 0, $header_size );
$body = substr( $response, $header_size );
curl_close( $ch );
//...
}
}
这段代码会初始化一个 cURL 句柄,设置各种选项,然后使用 curl_exec()
函数发送请求,获取响应内容。
5. 使用 Fsockopen (WP_HTTP_Fsockopen)
如果选择了 Fsockopen 方式,WP_HTTP_Fsockopen
类会使用 fsockopen()
函数来处理请求。
class WP_HTTP_Fsockopen {
public function request( $url, $args = array() ) {
$ssl = substr( $url, 0, 8 ) == 'https://';
$port = $ssl ? 443 : 80;
$host = parse_url( $url, PHP_URL_HOST );
$path = parse_url( $url, PHP_URL_PATH );
$query = parse_url( $url, PHP_URL_QUERY );
if ( $query ) {
$path .= '?' . $query;
}
$fp = fsockopen( ($ssl ? 'ssl://' : '') . $host, $port, $errno, $errstr, $args['timeout'] );
if ( ! $fp ) {
return new WP_Error( 'http_request_failed', $errstr, $errno );
}
$request = $method . ' ' . $path . ' HTTP/' . $args['httpversion'] . "rn";
$request .= "Host: " . $host . "rn";
$request .= implode( "rn", $headers ) . "rnrn";
$request .= $body;
fwrite( $fp, $request );
$response = '';
while ( ! feof( $fp ) ) {
$response .= fgets( $fp, 1160 );
}
fclose( $fp );
//...
}
}
这段代码会使用 fsockopen()
函数建立 socket 连接,手动构建 HTTP 请求,然后发送请求,读取响应内容。
6. 处理响应
无论使用哪种传输方式,wp_remote_request()
函数都会将响应内容解析成一个数组,包含了以下几个元素:
body
: 响应体。headers
: 响应头,是一个关联数组。response
: 一个数组,包含了 HTTP 状态码和状态信息。cookies
: 一个数组,包含了响应中的 cookies。filename
: 如果指定了文件名,那么这个元素会包含文件名。
$response = array(
'headers' => $headers,
'body' => $body,
'response' => array( 'code' => $status_code, 'message' => $status_text ),
'cookies' => $cookies,
'filename' => $args['filename'],
);
7. wp_remote_get()
:GET 请求的便捷方式
现在我们再来看看 wp_remote_get()
函数。它实际上只是 wp_remote_request()
函数的一个简单封装,专门用于发送 GET 请求。
function wp_remote_get( $url, $args = array() ) {
$defaults = array( 'method' => 'GET' );
$args = wp_parse_args( $args, $defaults );
return wp_remote_request( $url, $args );
}
可以看到,wp_remote_get()
函数只是简单地将 method
参数设置为 GET
,然后调用 wp_remote_request()
函数。
8. 错误处理
wp_remote_request()
函数会使用 WP_Error
对象来处理错误。如果请求失败,函数会返回一个 WP_Error
对象,包含了错误代码和错误信息。
if ( is_wp_error( $response ) ) {
// Handle the error
$error_code = $response->get_error_code();
$error_message = $response->get_error_message();
echo "Error: $error_code - $error_message";
} else {
// Process the response
$body = wp_remote_retrieve_body( $response );
//...
}
9. 实际应用
让我们来看一个实际的例子,使用 wp_remote_get()
函数获取一个网页的内容:
$url = 'https://www.example.com';
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) ) {
$error_message = $response->get_error_message();
echo "Something went wrong: $error_message";
} else {
$body = wp_remote_retrieve_body( $response );
echo $body;
}
这段代码会向 https://www.example.com
发送一个 GET 请求,如果请求成功,就会输出网页的内容。
10. 其他相关函数
wp_remote_post()
: 用于发送 POST 请求。wp_remote_head()
: 用于发送 HEAD 请求。wp_remote_retrieve_body()
: 用于从响应中提取响应体。wp_remote_retrieve_headers()
: 用于从响应中提取响应头。wp_remote_retrieve_response_code()
: 用于从响应中提取 HTTP 状态码。wp_remote_retrieve_response_message()
: 用于从响应中提取 HTTP 状态信息。
总结:HTTP 请求的艺术
wp_remote_get()
和 wp_remote_request()
函数是 WordPress 中处理远程 HTTP 请求的核心函数。它们提供了灵活和强大的功能,可以让我们轻松地与远程服务器进行交互。通过了解它们的源码,我们可以更好地理解 HTTP 请求的原理,并能够更加灵活地使用它们来解决实际问题。
结束语:代码的世界,探索永无止境!
希望今天的讲解能够帮助大家更好地理解 wp_remote_get()
函数的源码。记住,代码的世界是充满乐趣的,探索永无止境。下次遇到类似的问题,不妨自己动手调试一下,相信你会有更多的收获!感谢大家的聆听!