swoole基础-swoole之http服务器

今天我们来了解一下swoole内置的http服务器,这篇我们一开始没打算更新,想着后面写websocket的时候可能有个别知识点会让人觉得突兀,这才有了今天我们要说的内容。

为什么一开始没打算写swoole http服务器的内容呢?考虑到一般的web应用,现在都有非常成熟的开发框架,比如yii2\laravel\tp5\yaf等框架。如果说让你自己基于swoole再写一套应用层面的逻辑呢?比如路由解析,日志封装等等,不仅费时而且费力。

言归正传,我们看本文主题。

swoole_http_server

swoole_http_server继承自swoole_server,用于创建swoole版的http服务器。php也可以自己创建http服务器了?对,你没听错,是http服务器。

所谓的http服务器,其含义就是一旦我们部署好,用户便可以直接通过浏览器访问该服务器。理论上而言,我们不需要再借用nginx或者httpd部署,是不是很神奇?但是,理论归理论,swoole_http_server对HTTP协议的支持还不成熟,所以实际,我们还是需要用nginx作为代理。

虽然swoole_http_server继承自swoole_server,但是除了onConnect/onReceive回调不能用之外,swoole_server提供的其他API函数都可以直接使用,跟我们先前学到的内容无缝对接!另外,虽然废除了onReceive回调,swoole_http_server却为我们新增了onRequest回调,该回调会在接收到一个http请求之后被调用。

下面我们创建一个简单的http服务器。

1
2
3
4
5
6
7
8
<?php

$http = new swoole_http_server("127.0.0.1", 8000);
$http->on('request', function (swoole_http_request $request, swoole_http_response $response) {
$response->status(200);
$response->end('hello world.');
});
$http->start();

$http 是swoole_http_server的一个对象,onRequest回调接收两个参数分别是swoole_http_request对象和swoole_http_response对象,分别负责request请求和response响应,这两个我们等会再说。

swoole_http_server的start方法用于启动该server。

CLI下运行该脚本,我们创建一个监听本地8000端口的HTTP服务器,如果该端口被占用,可以更换其他未被占用的端口。

server启动之后,我们就可以用浏览器对该监听该端口的http server发起一个http请求,浏览器地址栏访问 http://127.0.0.1:8000 后我们可以看到页面上有输出”hello world.”字样。

作为应用服务器,单纯的输出hello world的意义不大。如果要丰富应用层,就需要让onRequest回调丰富起来,这也就需要我们熟悉onRequest回调的两个参数,http请求和http响应的处理。

swoole_http_request

swoole_http_request,负责http请求的相关信息。我们可以在这个对象上,获取header\server\get\post\files\cookie等信息,这等同于php的超全局变量,但是这可不是超全局的,request关联的这些信息可能不存在。我们来看一个例子

1
2
3
4
5
6
7
$http->on('request', function (swoole_http_request $request, swoole_http_response $response) {

print_r($request);

$response->status(200);
$response->end('hello world.');
});

server在onRequest回调内打印swoole_http_request信息,我们用chrome浏览器访问下 http://127.0.0.1:8000/

看server终端打印的信息,首先我解释一个非重要信息,server终端会打印出两个 swoole_http_request Object,这是因为第二个是 /favicon.ico 请求,忽略就好,后面我们用nginx部署好,在应用的根目录下添加一个 favicon.ico 就不会有这个请求问题了。

我们看server所在终端打印的 swoole_http_request Object,发现有下面这些属性

fd 客户端标识
header 请求的头信息,你可以对比下浏览器实际发出的request header,结果是一样的
server 请求相关的服务器信息
还有一项data,HTTP请求的详细信息
get在哪里呢?木有get信息,我们再访问下这个路由 http://127.0.0.1:8000/pathinfo?id=123 ,看看server终端打印的信息里是不是多了一项get属性?

现在我们可以在onRequest回调内,通过$request->server来获取URI信息,也可以通过$request->get获取get相关的信息等等。

可以进一步说,如果我们继续在onRequest回调内根据 swoole_http_request->server[‘request_uri’]做好路由解析,把不同的路由解析到不同的 php 类文件,swoole版的http请求便被我们用活了。案例这里就不说了,有兴趣的可以去github上搜一搜大牛的源码学习学习。

swoole_http_response

swoole_http_response,负责处理HTTP响应信息,包括响应的头信息header\响应状态等。

比如上例中 $response->status() 设置响应状态码,$response->end() 发送响应体并结束请求。

其实都没有什么要说的,跟传统的HTTP请求和响应差别不大。

swoole_http_request和swoole_http_response对象的细节,还请多翻阅官方手册。

下面我们主要看看实际的部署问题。

nginx代理

即使swoole_http_server再牛逼,他现在也没赶超老牌的nginx,所以,在http请求上,我们还是靠nginx来处理,通过nginx把请求转发给swoole,如此一来你有没有发现整个逻辑少了fpm?没错,nginx+swoole顺利上位。

下面我们配置一个域名叫 “swoole.example.com”的站看看。

首先我们把监听8000端口的swoole_http_server打开,然后nginx添加如下的配置,重启nginx后,我们访问下 swoole.example.com 看看结果。不要忘记配置host哦

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
root /var/www/test/;
server_name swoole.example.com;
index index.php index.html;

location / {
if (!-e $request_filename) {
proxy_pass http://127.0.0.1:8000;
}
}
}

默认 /var/www/test/ 目录下我们没有任何文件,空目录,location中我们判断如果访问的文件不存在,就转发到本地的8000端口即swoole_http_server。

我们访问下 http://swoole.example.com/index.html ,index.html是不存在的,按照nginx的逻辑,这个请求会被转发到本地的8000端口,所以结果页面展示的是hello world. 没有问题。也就是说现在我们成功的使用了nginx代理,swoole处理业务逻辑层。

后面,我们主要来说说websocket那些事。