问题
I'm writing a plugin for wordpress that needs to call an API for every request the user makes.
These API-calls are done using the HTTPS protocol. Currently, for every new user request, I need to reopen the HTTPS connection.
Yes, curl allows persistent connections (reusing the handle or using the multi handle) but I would like to persist the connection throughout multiple user requests.
So: Is it possible to keep a HTTPS connection open throught multiple PHP processes and reuse it? The alternative would be to let the user's browser to the API-talk. But if it is possible I would like to avoid that.
回答1:
While many will tell you PHP wasn't designed for this (and they're technically correct), this kind of problem has been solved already by using a persistent event loop. e.g. server-side concurrency is achieved with JavaScript by using node.js, which starts a loop running on a single thread that listens for events. Instead of the typical PHP setup which starts a new thread every request it receives from the webserver, you can use a similar architecture with the (unfortunately named) ReactPHP.
The biggest hitch to your concept is that it's running as a WordPress plugin. WordPress tends to be extremely lowest-common-denominator, so you're going to need to exclude a few installs if you want this to work. The biggest trick is that you're not going to be able to (easily) use your WordPress-routed pages to load from this ReactPHP loop. I know you're trying to avoid extra connections, but you can get this running at a much lower latency by connecting to your local ReactPHP server, instead of getting a remote connection each time.
If your server will give you access to open some local ports, you can create a new ReactPHP server like so:
$socket = new React\Socket\Server(8080, $loop);
If you don't have port access, you may be able to setup your connection through a local socket. This can take a bit more to setup and would be trickier to get working on a general install:
$socket = new React\Socket\Server('unix://path/to/unix/socket', $loop);
I haven't gone through the steps to set that up, but if you can get that to work, I think it would be the most reliable approach for WordPress since you will always have some filesystem access inside your plugins.
You should be able to see how to drop in your persistent connection, either with the Closure
you build your server with, or some static class method (preferred, since then that class could be responsible for reconnecting whenever it's dropped).
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 */)
);
});
I'll leave writing the ExternalService
bit up to you, since I'm sure you have something setup here already.
For your WordPress pages, they can now make their requests to your extremely-low-latency local ReactPHP. You can try fsockopen if you want to use sockets, or a simple curl if you do it over TCP.
Another sticking point will be initialising the server. If it's a server you own, have shell access to, can run cron
jobs, or have exec()
it's very simple: just run your server script. Otherwise, you'll need to put in some hours to config your server to run this script on a new request and not time it out.
The other option is to flip it around: if you can make the entire app served under ReactPHP (instead of hitting the WP dispatcher first), you can do this without all the local-connections and jump straight to the persistent connection. This would make distributing it as a WordPress plugin impossible, of course.
When it's all said and done, you should ask yourself if saving the latency on these requests is really worth the effort. I'm not you so I can't say, but if you really need to keep using WordPress or PHP, this is how you can do it. You'll find it's an exponentially simpler problem if you can drop the WordPress part (maybe make //mydomain.com/blog
go to WP, and everything else serve from your ReactPHP app). If you can move off of PHP, it moves from simpler to probably easier to configure with a persistent connection than without, as this is a standard approach in node or Go. Architecturally it's not much different than connecting to your DB when the server starts up, instead of on every connection.
回答2:
I ended up making these requests through the browser. Browsers keep HTTP(S) connections open when the server tells them to.
Alas, this solution entails some disadvantages:
- authentication is more difficult
- more load on the server as more connections have to be maintained
- the solution needs additional JavaScript
But requests are much faster (about 3x) and load on the server where WordPress is running is minimized.
来源:https://stackoverflow.com/questions/45265014/php-keep-https-connection-to-api-open-throughout-multiple-requests