CURLRequest 类
CURLRequest
类是一个轻量级的基于 CURL 的 HTTP 客户端,允许你与其他网站和服务器进行通信。它可以用于获取谷歌搜索的内容、检索网页或图片,或与 API 进行通信等多种用途。
这个类模仿了 Guzzle HTTP 客户端 库,因为它是使用最广泛的库之一。在可能的情况下,语法保持相同,所以如果你的应用程序需要比这个库提供的功能更强大的东西,你将需要做很少的改变就可以过渡到使用 Guzzle。
备注
这个类需要你的 PHP 版本中安装 cURL 库。这是一个非常常见的库,通常是可用的,但并非所有主机都会提供它,所以如果你遇到问题,请与你的主机确认。
CURLRequest 配置
共享选项
重要
这个设置只是为了向后兼容而存在。在新项目中不要使用它。即使你已经在使用它,我们也建议你禁用它。
备注
自 v4.4.0 起,其默认值已被改为 false
。
如果你想在多个请求之间共享所有选项,请在 app/Config/CURLRequest.php 中将 $shareOptions
设置为 true
:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class CURLRequest extends BaseConfig
{
// ...
public bool $shareOptions = true;
}
如果你使用该类的实例发送多个请求,此行为可能会导致发送不必要的头部和正文的错误请求。
备注
在 v4.2.0 之前,即使 $shareOptions
为 false,由于一个 bug,请求消息体也不会被重置。
加载库
可以通过手动方式或通过 Services 类 来加载该库。
要通过 Services 类调用,使用 curlrequest()
方法或全局函数 service()
:
<?php
$client = service('curlrequest'); // Since v4.5.0, this code is recommended due to performance improvements
// The code above is the same as the code below.
$client = \Config\Services::curlrequest();
你可以在第一个参数中传递默认选项数组来修改 cURL 将如何处理请求。选项将在下文中描述:
<?php
$options = [
'baseURI' => 'http://example.com/api/v1/',
'timeout' => 3,
];
$client = service('curlrequest', $options);
备注
当 $shareOptions
为 false 时,传递给类构造函数的默认选项将用于所有请求。在发送请求后,其他选项将被清除。如果你想对所有请求使用选项,请在构造函数中传递选项。
手动创建类时,你需要传递一些依赖项。第一个参数是一个 Config\App
类的实例。第二个参数是一个 URI 实例。第三个参数是一个 Response 对象。第四个参数是可选的默认 $options
数组:
<?php
use Config\App;
$client = new \CodeIgniter\HTTP\CURLRequest(
config(App::class),
new \CodeIgniter\HTTP\URI(),
new \CodeIgniter\HTTP\Response(config(App::class)),
$options
);
使用该库
使用 CURL 请求非常简单,只需创建请求并获取返回的 Response 对象。它旨在处理通信。之后你可以完全控制信息的处理方式。
发起请求
大部分通信是通过 request()
方法完成的,它会发出请求,然后返回一个 Response 实例给你。它以 HTTP 方法、URL 和选项数组作为参数。
<?php
$client = service('curlrequest');
$response = $client->request('GET', 'https://api.github.com/user', [
'auth' => ['user', 'pass'],
]);
重要
默认情况下,如果返回的 HTTP
代码大于或等于 400,CURLRequest 将抛出 HTTPException
。如果你想获取响应,
请查看 http_errors 选项。
备注
当 $shareOptions
为 false 时,传入方法的选项将用于该请求。发送请求后,选项将被清除。如果你想对所有请求使用选项,请在构造函数中传入选项。
由于响应是一个 CodeIgniter\HTTP\Response
实例,你可以使用所有正常的信息:
<?php
echo $response->getStatusCode();
echo $response->getBody();
echo $response->header('Content-Type');
$language = $response->negotiateLanguage(['en', 'fr']);
虽然 request()
方法是最灵活的,你也可以使用以下快捷方法。它们都以 URL 作为第一个参数,选项数组作为第二个参数:
<?php
$client->get('http://example.com');
$client->delete('http://example.com');
$client->head('http://example.com');
$client->options('http://example.com');
$client->patch('http://example.com');
$client->put('http://example.com');
$client->post('http://example.com');
基本 URI
可以在实例化类时将 baseURI
作为一个选项传入。这允许你设置一个基本 URI,然后使用相对 URL 对该客户端的所有请求进行调用。当与 API 一起使用时,这特别方便:
<?php
$client = service('curlrequest', [
'baseURI' => 'https://example.com/api/v1/',
]);
// GET http:example.com/api/v1/photos
$client->get('photos');
// GET http:example.com/api/v1/photos/13
$client->delete('photos/13');
当向 request()
方法或任何快捷方法提供相对 URI 时,它将根据 RFC 2986 部分 2 描述的规则与 baseURI 组合。
为了节省你一些时间,这里有一些组合结果的示例。
baseURI
URI
结果
http://foo.com
/bar
http://foo.com/bar
http://foo.com/foo
/bar
http://foo.com/bar
http://foo.com/foo
bar
http://foo.com/bar
http://foo.com/foo/
bar
http://foo.com/foo/bar
http://foo.com
http://baz.com
http://baz.com
http://foo.com/?bar
bar
http://foo.com/bar
使用响应
每个 request()
调用都会返回一个 Response 对象,其中包含大量有用的信息和一些有用的方法。最常用的方法让你确定响应本身。
你可以获取响应的状态码和原因短语:
<?php
$code = $response->getStatusCode(); // 200
$reason = $response->getReasonPhrase(); // OK
你可以从响应中检索标头:
<?php
// Get a header line
echo $response->getHeaderLine('Content-Type');
// Get all headers
foreach ($response->headers() as $name => $value) {
echo $name . ': ' . $response->getHeaderLine($name) . "\n";
}
可以使用 getBody()
方法获取消息体:
<?php
$body = $response->getBody();
消息体是远程服务器提供的原始消息体。如果内容类型需要格式化,则需要确保脚本对其进行处理:
<?php
if (str_contains($response->header('content-type'), 'application/json')) {
$body = json_decode($body);
}
请求选项
本节描述了可以传递到构造函数、request()
方法或任何快捷方法中的所有可用选项。
allow_redirects
默认情况下,cURL 不会跟随远程服务器发送回的任何 “Location:” 头。allow_redirects
选项允许你修改这种行为。
如果你将该值设置为 true
,那么它将会跟随重定向:
<?php
$client->request('GET', 'http://example.com', ['allow_redirects' => true]);
/*
* Sets the following defaults:
* 'max' => 5, // Maximum number of redirects to follow before stopping
* 'strict' => true, // Ensure POST requests stay POST requests through redirects
* 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols
*/
警告
请注意,启用重定向可能会重定向到你未预期的 URL,并可能导致 SSRF 攻击。
将其设置为 false
将对请求应用默认设置:
<?php
$client->request('GET', 'http://example.com', ['allow_redirects' => false]);
你可以将数组作为 allow_redirects
选项的值传递,以指定新的设置以代替默认设置:
<?php
$client->request('GET', 'http://example.com', ['allow_redirects' => [
'max' => 10,
'protocols' => ['https'], // Force HTTPS domains only.
]]);
备注
当 PHP 在 safe_mode 中或启用 open_basedir 时,跟随重定向将不起作用。
auth
允许你为 HTTP 基本认证 和 摘要认证 提供认证细节。你的脚本可能需要做额外的工作来支持摘要认证 - 这只是简单地为你传递用户名和密码。值必须是一个数组,其中第一个元素是用户名,第二个是密码。第三个参数应该是要使用的认证类型,可以是 basic
或 digest
:
<?php
$client->request('GET', 'http://example.com', ['auth' => ['username', 'password', 'digest']]);
body
对于支持 body 的请求类型(如 PUT、POST 等),有两种方式设置请求 body。第一种方式是使用 setBody()
方法:
<?php
$client->setBody($body)->request('PUT', 'http://example.com');
第二种方法是通过传递一个 body
选项。这是为了保持 Guzzle API 的兼容性,功能完全相同。值必须是一个字符串:
<?php
$client->request('PUT', 'http://example.com', ['body' => $body]);
cert
要指定客户端证书的位置,需要以字符串形式传递包含完整路径的 cert
选项。如果需要密码,请将值设置为一个数组,其中第一个元素是证书的路径,第二个是密码:
<?php
$client->request('GET', '/', ['cert' => ['/path/server.pem', 'password']]);
connect_timeout
默认情况下,CodeIgniter 不对 cURL 尝试连接到网站的时间施加限制。如果你需要修改此值,可以以秒为单位传递 connect_timeout
选项。你可以传递 0 以无限期等待:
<?php
$client->request('GET', 'http://example.com', ['connect_timeout' => 0]);
debug
当 debug
被传递并设置为 true
时,这将在脚本执行期间启用写入 STDERR 的其他调试信息。
这是通过传递 CURLOPT_VERBOSE
并回显输出来完成的。因此,当你通过 spark serve
运行内置服务器时,你会在控制台中看到输出。否则,输出将被写入服务器的错误日志中。
<?php
$client->request('GET', 'http://example.com', ['debug' => true]);
你可以将文件名作为 debug 的值以将输出写入文件:
<?php
$client->request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']);
delay
允许在发送请求之前暂停一定的毫秒数:
<?php
// Delay for 2 seconds
$client->request('GET', 'http://example.com', ['delay' => 2000]);
form_params
你可以通过在 form_params
选项中传递关联数组来发送 application/x-www-form-urlencoded POST 请求中的表单数据。如果尚未设置,这将设置 Content-Type
标头为 application/x-www-form-urlencoded
:
<?php
$client->request('POST', '/post', [
'form_params' => [
'foo' => 'bar',
'baz' => ['hi', 'there'],
],
]);
备注
form_params
不能与 multipart 选项一起使用。你需要使用其中一个。对 application/x-www-form-urlencoded
请求使用 form_params
,对 multipart/form-data
请求使用 multipart
。
headers
虽然你可以使用 setHeader()
方法设置此请求需要的任何标头,但你也可以将关联数组的标头作为选项传递。每个键都是标头的名称,每个值是表示标头字段值的字符串或字符串数组:
<?php
$client->request('GET', '/', [
'headers' => [
'User-Agent' => 'testing/1.0',
'Accept' => 'application/json',
'X-Foo' => ['Bar', 'Baz'],
],
]);
如果标头被传递到构造函数中,它们会被视为默认值,并被后续的标头数组或对 setHeader()
的调用覆盖。
http_errors
默认情况下,如果返回的 HTTP 状态码大于等于 400,CURLRequest 将抛出 HTTPException
异常。
如果你想查看响应正文,可以将 http_errors
设置为 false
,以返回内容而不是抛出异常:
<?php
$client->request('GET', '/status/500');
// If the response code is 500, an HTTPException is thrown,
// and a detailed error report is displayed if in development mode.
$response = $client->request('GET', '/status/500', ['http_errors' => false]);
echo $response->getStatusCode(); // 500
echo $response->getBody(); // You can see the response body.
json
json
选项用于轻松地将 JSON 编码的数据作为请求的 body 上传。添加了 application/json
的 Content-Type 标头,覆盖任何可能已经设置的 Content-Type。传给此选项的数据可以是 json_encode()
接受的任何值:
<?php
$response = $client->request('PUT', '/put', ['json' => ['foo' => 'bar']]);
备注
此选项不允许自定义 json_encode()
函数或 Content-Type 标头。如果你需要那种能力,你需要手动编码数据,通过 CURLRequest 的 setBody()
方法传递它,并使用 setHeader()
方法设置 Content-Type 标头。
multipart
当你需要通过 POST 请求发送文件和其他数据时,可以使用 multipart
选项,以及 CURLFile 类。
这些值应该是一个关联数组,包含要发送的 POST 数据。为了更安全地使用,前缀带有 @
的旧方法已被禁用。任何你想发送的文件必须作为 CURLFile 的实例传递:
<?php
$client->request('POST', '/post', [
'multipart' => [
'foo' => 'bar',
'userfile' => new \CURLFile('/path/to/file.txt'),
],
]);
备注
multipart
不能与 form_params 选项一起使用。你只能使用其中一个。使用 form_params
进行 application/x-www-form-urlencoded
请求,使用 multipart
进行 multipart/form-data
请求。
proxy
在 4.4.0 版本加入.
你可以通过将关联数组作为 proxy
选项来设置代理:
<?php
$client->request(
'GET',
'http://example.com',
['proxy' => 'http://localhost:3128']
);
query
你可以通过作为 query
选项传递关联数组,来传递要作为查询字符串变量发送的数据:
<?php
// Send a GET request to /get?foo=bar
$client->request('GET', '/get', ['query' => ['foo' => 'bar']]);
timeout
默认情况下,允许 cURL 函数无限期运行,没有时间限制。你可以使用 timeout
选项对其进行修改。值应该是你希望函数执行的秒数。使用 0 表示无限期等待:
<?php
$client->request('GET', 'http://example.com', ['timeout' => 5]);
user_agent
允许指定请求的用户代理:
<?php
$client->request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']);
verify
此选项描述了 SSL 证书验证行为。如果 verify
选项为 true
,它将启用 SSL 证书验证并使用操作系统提供的默认 CA 包。如果设置为 false
,它将禁用证书验证(这是不安全的,并允许中间人攻击!)。你可以将其设置为包含 CA 包路径的字符串,以使用自定义证书启用验证。默认值为 true:
<?php
// Use the system's CA bundle (this is the default setting)
$client->request('GET', '/', ['verify' => true]);
// Use a custom SSL certificate on disk.
$client->request('GET', '/', ['verify' => '/path/to/cert.pem']);
// Disable validation entirely. (Insecure!)
$client->request('GET', '/', ['verify' => false]);
version
要设置要使用的 HTTP 协议,你可以传递带有版本号的字符串或浮点数(通常为 1.0
或 1.1
,v4.3.0 开始支持 2.0
)。
<?php
// Force HTTP/1.0
$client->request('GET', '/', ['version' => 1.0]);