license 验证服务器唯一机器码_Swoole实现API服务器

8d4ed01a8795fd6433be5d5471753a11.png

Swoole实际上并不单是PHP中的一个扩展,从它的定位中,我们可以看出它实际上是可以直接替代服务层的。

从官方文档:https://wiki.swoole.com/wiki/page/326.html中就可以看出,Swoole实际上可以代替nginx,作为代理http的服务应用。

下面我们就来学习下如何使用Swoole/Http/Server,搭建HTTP-API服务。

目录结构:

server.php 服务启动脚步
vendor 公共文件类
app 接口文件地址 ,规则为:版本号/业务名称/接口文件(类同名) 

server.php代码

<?php
// +----------------------------------------------------------------------
// Swoole - HTTP-SERVER-API
// +----------------------------------------------------------------------
// Copyright (c) 2018 https://xiuxian.junphp.com All rights reserved.
// +----------------------------------------------------------------------
// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// Author: 小黄牛 <1731223728@qq.com>
// +----------------------------------------------------------------------
ini_set('display_errors', 1); 
error_reporting(E_ALL ^ E_NOTICE);
require_once dirname(__FILE__).'/vendor/api.php';
$server = new server();
$server->run();
class server{
    /**
     * WS的启动实例
    */
    private $_ws;
    /**
     * host-IP,0.0.0.0表示允许接收所有请求
    */
    private $_host = '0.0.0.0';
    /**
     * 端口号
    */
    private $_port = '9501';
    /**
     * 这是启动服务端的入口
    */
    public function run() { 
        $this->start();
        $this->onRequest();
        $this->_ws->start();
    }
    /**
     * 启动http-server服务
    */
    private function start() {
        # 创建websocket服务器对象,监听0.0.0.0:9502端口
        $this->_ws = new swoole_http_server($this->_host, $this->_port);
        $this->_ws->set([
            'worker_num' => 4,
            'max_request' => 500
        ]);
    }
    /**
     * 监听回调请求
    */
    private function onRequest() {
        $this->_ws->on('request', function ($request, $response) {
            # 防止Chrome的空包
            $uri = $request->server['request_uri'];
            if ($uri == '/favicon.ico') {
                $response->status(404);
                $response->end();
            } else {
                # 先验证下请求头
                api::check($request->header);
                # 先验证下SIGN
                $data = api::param($request);
                $res = api::sign_vif($data);
                if ($res !== true) {
                    $response->end($res);
                } else {
                    # 继续向下执行
                    $this->follow_up_route($request, $response, $data);
                }
            }
        });
    }
    /**
     * 请求API检测
    */
    private function follow_up_route($request, $response, $param) {
        $referer = ltrim($request->server['request_uri'], '/');
        # 分割路由
        $array = explode('/', $referer);
        if (count($array) < 2) {
            $response->end(api::json('50001', '请求地址错误,格式为:版本号/业务名/接口名'));
        } else {
            $path = dirname(__FILE__).'/app';
            $edition = $path.'/'.$array[0];
            if (!file_exists($edition)) {
                $response->end(api::json('50002', '暂无该版本'));
            } else {
                $controller = $edition.'/'.$array[1];
                if (!file_exists($controller)) {
                    $response->end(api::json('50003', '暂无该业务'));
                } else {
                    if (!empty($array[2])) {
                        $action_name = $array[2];
                    } else {
                        $action_name = 'index';
                    }
                    $action = $controller.'/'.$action_name.'.php';
                    if (!file_exists($action)) {
                        $response->end(api::json('50004', '暂无该接口'));
                    } else {
                        $this->follow_up_transmit($request, $response, $param, $action, $action_name);
                    }
                }
            }
        }
    }
    /**
     * 请求接口转发
    */
    private function follow_up_transmit($request, $response, $param, $action, $action_name) {
        # 引入接口文件
        require_once $action;
        # 实例化接口
        $obj = new $action_name();
        $obj->run($request, $response, $param, new api);
    }
}

其中我们需要注意,request事件在Chrome内核的浏览器请求下,会由一次空包请求,官方解释:https://wiki.swoole.com/wiki/page/445.html

所以需要通过$request->server['request_uri']参数来拦截第一次空包请求,防止逻辑错乱。

通过follow_up_transmit()最后,我们加载对应的API接口文件。

下面我们来看下一个简单的app/v1/login/index.php接口的代码:

<?php
// +----------------------------------------------------------------------
// | 登录接口
// +----------------------------------------------------------------------
// | Copyright (c) 2018 https://xiuxian.junphp.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 小黄牛 <1731223728@qq.com>
// +----------------------------------------------------------------------
class index {
    /**
     * 接口请求入口
     * @param obj $request
     * @param obj $response 
     * @param array $param 
     * @param obj $api    
     * @return bool
    */
    public function run($request, $response, $param, $api){
        $res = $this->is_type($request, $response, $api, 'get');
        if ($res !== true) {
            $response->end($res);
        } else {
            $response->end($api::json('200', '请求成功', $param));
        }
    }
    // 判断请求类型
    private function is_type($request, $response, $api, $is_type) {
        # 拿出类型
        $type = strtolower($request->server['request_method']);
        if ($type != $is_type) {
            return $api::json('50000', '请求类型错误!');
        }
        return true;
    }
}

在linux通过php server.php启动服务后。

我们就可以在浏览器中访问 IP:9501/v1/login/index 或者 IP:9501/v1/order/get进行访问测试了。

进过一台4核8G 1M带宽的阿里云测试,命令为:

ab -c 700 -n 5000 -k http://你的IP:9501/v1/login/index?id=1

得出极限并发数为700,超过这个数就会出现丢包。

32edaa379dc16950b70394c4b6256315.png

因为带宽原因,没能测试极限并发量,但也明显能够看出,swoole作为http服务引擎,也是很棒的存在,而且作为一名PHP开发者,用PHP编写http-api服务,可控性也会高很多。


最后推荐大家可以用下我开源的一个基于Swoole4.5+研发的PHP框架。该框架基于注解实现了很多好玩的功能,很适合新人快速上手Swoole扩展。

SW-X框架-专注高性能便捷开发而生的PHP-SwooleX框架​www.sw-x.cn
3c5890599a4bc7ee3ebffca377fe8db6.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值