PHP:在多个请求中保持与 API 的 HTTPS 连接打开

Posted

技术标签:

【中文标题】PHP:在多个请求中保持与 API 的 HTTPS 连接打开【英文标题】:PHP: Keep HTTPS Connection to API open throughout multiple requests 【发布时间】:2017-12-29 02:52:59 【问题描述】:

我正在为 wordpress 编写一个插件,它需要为用户提出的每个请求调用一个 API。

这些 API 调用是使用 HTTPS 协议完成的。 目前,对于每个新用户请求,我都需要重新打开 HTTPS 连接。

是的,curl 允许持久连接(重用句柄或使用多句柄),但我想在多个用户请求中保持连接。

那么:是否可以通过多个 php 进程保持 HTTPS 连接打开并重用它?另一种方法是让用户的浏览器与 API 对话。但如果可能的话,我想避免这种情况。

【问题讨论】:

PHP 的设计初衷并非如此。但是,理论上你可以在 PHP 中使用create a socket server,它在 Apache/nginx 之外的自己的端口上运行并打开持久的 HTTPS 连接,然后将所有用户请求发送到该端口,以便它可以处理 API 调用。 哦,这很讨厌。我需要实现 HTTP/S 服务器 + 客户端,并且不能保证它可以正常工作,因为 wordpress 站点可能(应该)有防火墙。 其他人如何解决这个问题。他们只是接受新 HTTPS 连接的巨大延迟成本吗?肯定有写PHP代码的人无法接受。 嗯,从技术上讲,HTTPS 也被设计为一次执行一个请求。所以是的,几乎每个人都在接受多个连接的开销。大多数远程 API 并非旨在通过单个 HTTPS 连接接受多个请求。 你在开玩笑吗?真的吗?为什么大多数 API 不能通过 HTTPS 接受多个请求?只需在它前面放一个 NGINX ......他们在每个请求中浪费了大约 3.5 倍的延迟?看来这里确实有些不对劲…… 【参考方案1】:

虽然很多人会告诉您 PHP 不是为此而设计的(而且他们在技术上是正确的),但这种问题已经通过使用持久事件循环得到了解决。例如服务器端并发是通过使用 node.js 使用 javascript 实现的,它启动一个在单个线程上运行的循环以侦听事件。与典型的 PHP 设置不同,它会在它从网络服务器收到的每个请求中启动一个新线程,您可以使用类似的架构与(不幸地命名为)ReactPHP。

您的概念最大的障碍是它作为 WordPress 插件运行。 WordPress 往往是非常最低公分母,因此如果您希望它起作用,您将需要排除一些安装。最大的技巧是您将无法(轻松)使用您的 WordPress 路由页面从这个 ReactPHP 循环加载。我知道您正在尝试避免额外的连接,但是您可以通过连接到本地 ReactPHP 服务器来以更低的延迟运行它,而不是每次都获得远程连接。

如果你的服务器允许你打开一些本地端口,你可以像这样创建一个新的 ReactPHP 服务器:

$socket = new React\Socket\Server(8080, $loop);

如果您没有端口访问权限,则可以通过本地套接字设置连接。这可能需要更多的设置时间,并且在进行常规安装时会更加棘手:

$socket = new React\Socket\Server('unix://path/to/unix/socket', $loop);

我还没有完成设置步骤,但是如果你可以让它工作,我认为这将是 WordPress 最可靠的方法,因为你总是有一些文件系统访问您的插件。

您应该能够看到如何使用Closure 来构建您的服务器,或者使用一些静态类方法(首选,因为从那时起该类可以负责在它被丢弃时重新连接) .

use React\Http\Server;
use Psr\Http\Message\ServerRequestInterface as Request;
use React\Http\Response;
use MyNamespace\Api\ExternalService;

$server = new Server(function (Request $request) 
    $ch = ExternalService::getConnectionHandle();
    // Do something with your $ch based on the $request here

    return new Response(
        200,
        ['Content-Type' => 'application/json'],
        json_encode(/* some data from your request */)
    );
);

我将把ExternalService 留给你写,因为我确定你已经在这里设置了一些东西。

对于您的 WordPress 页面,他们现在可以向您的极低延迟本地 ReactPHP 发出请求。如果你想使用套接字,你可以尝试fsockopen,或者如果你通过 TCP 来使用简单的 curl。

另一个难点是初始化服务器。如果它是您拥有的服务器,可以访问 shell,可以运行 cron 作业,或者拥有 exec(),这非常简单:只需运行您的服务器脚本。否则,您将需要花费几个小时来配置您的服务器,以便在新请求上运行此脚本并且不会超时。

另一种选择是翻转它:如果您可以让整个应用程序在 ReactPHP 下提供服务(而不是先点击 WP 调度程序),您可以在没有所有本地连接的情况下执行此操作并直接跳转到持久连接。当然,这会使它无法作为 WordPress 插件分发。

说完这些,您应该问问自己,节省这些请求的延迟是否真的值得付出努力。我不是你,所以我不能说,但如果你真的需要继续使用 WordPress 或 PHP,你可以这样做。如果您可以删除 WordPress 部分,您会发现这是一个指数级更简单的问题(也许让 //mydomain.com/blog 转到 WP,其他一切都从您的 ReactPHP 应用程序提供)。如果您可以脱离 PHP,那么使用持久连接配置它会从更简单变为可能更容易配置,因为这是 node 或 Go 中的标准方法。在架构上,它与在服务器启动时连接到您的数据库没有太大区别,而不是在每个连接上。

【讨论】:

unfortunate ReactPHP 这个名字怎么样? @hanshenrik 大约在同一时间,React javascript 库由 facebook 发布。它的方式,方式更受欢迎。因此,您不能说使用“react”,特别是因为 web 开发人员几乎总是使用 PHP,所以您必须说“reactphp”。【参考方案2】:

我最终通过浏览器发出这些请求。 当服务器要求浏览器打开 HTTP(S) 连接时,浏览器会保持打开状态。

唉,这个解决方案有一些缺点:

认证比较困难 由于需要维护更多的连接,服务器上的负载会增加 解决方案需要额外的 JavaScript

但是请求要快得多(大约 3 倍),并且运行 WordPress 的服务器上的负载最小化。

【讨论】:

以上是关于PHP:在多个请求中保持与 API 的 HTTPS 连接打开的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PHP 中发出 Https 请求

在 Web Api 中找到多个与请求匹配的操作

在 Web Api 中找到多个与请求匹配的操作

Spotify API:使用 PHP 请求

Python 中的 API 调用身份验证(工作 PHP 示例)

PHP CloudFront 代理/通过 API 转发视频流请求