(在项目中学习技术)完成使用swoole完成App二维码扫码登录网页端的操作

22 阅读4分钟

前言:大家好,我自己有一个项目完成度已经很高了,我自己的技术怎么说也不是太强,在完成这个项目中我学习很多知识,比如说使用swoole实现二维码登录,说实在的,我本身是一个前端,但是日常学习和工作中也会写一下php代码,swoole怎么说呢,也算是专业对口,在断断续续研究一个星期后,我也完成了app扫码登录的功能,怎么说,也算有个新技术傍身,到时候面试的时候还可以跟面试官吹吹牛。 首先呢先要介绍下我这个某某项目的要求和情况,因为毕竟有版权,我不会透露什么项目实际名称,实际上呢是这样的,这个项目分为安卓端(原生),ios端(原生),和网页端(vue),安卓和ios我不懂,这是别人完成的,我们这期的技术是使用swoole二维码登录,这当然是大部分网页端需要实现的功能,苦逼的我只能看了又看,做了又做了。 其实swoole的部署实际是后端接口api的事情,但是我们是一个小项目,php我也会弄,所以就兼职了一下,前面说了这么多,我们就不废话了,开始吧 什么是swoole,我其实不知道,因为用过php,我一直以为是php某个框架上的功能,我把扩展加上去就可以用了,比如laravel框架什么的,看了一个星期的,怎么说呢,其实不是这个样子,因为swoole其实是一个服务器,我们在实现代码后,swoole就会如同apache一样,你去访问请求这个地址,他会根据代码来输出数据,跟apache真的很像,而我们使用了他socket功能,先使用网页(就是请求)访问跟他这个swoole服务器建立连接后,我们会返回一个通道的id,这个id会通过二维码展示出来,然后手机去扫描这个二维码后,获得这个id,然后将手机登录时候获得token(登录验证唯一数据,需要安全保存)和这个id发送给这个swoole服务器连接通道(通过id来判断是哪个通道),通道收到请求后,会发送请求给网页,这个请求数据就包含token,然后网页把token保存起来,再跳转到主页,完成了登录,随后关闭swoole通道连接。

下面我通过代码来给大家解释

首先我们要给php加上swoole的扩展这个具体的请看我MAMP安装swoole记录,踩坑记录

1.新建swoole服务器

$this->server = new Swoole\WebSocket\Server("127.0.0.1", 9501);

2.监听swoole服务是否运行

$this->server->on('start', function ($server) { echo "Websocket Server is started at ws://127.0.0.1:9501\n"; });

3.swoole运行后,监听是否有人和swoole建立了连接,前端如果swoole建立了连接,相当于一个通道,他们之间就可以互相发送信息(1)前端建立与swoole连接后

swoole代码: image.png js代码前端连接swoole服务器的代码

function handShake() {
    qrCodeData.status = 'start'
    qrCodeData.errorInfo = '正在加载'
    getLoginQrCodeUrl()
    var wsServer = 'ws://127.0.0.1:9501';

    var websocket = new WebSocket(wsServer);
    //如果与服务器链接成功,则生成url二维码
    websocket.onopen = function () {
        qrCodeData.status = 'ready'
        qrCodeData.errorInfo = '服务器连接成功'
        websocket.send(JSON.stringify({ test: data.login }));
    };

    websocket.onclose = function () {
        if (qrCodeData.status != 'error') {
            qrCodeData.errorInfo = '二维码失效,请重新链接'
            qrCodeData.status = 'close'
        }
    };

    websocket.onmessage = function (evt) {
        console.log('Retrieved data from server: ' + evt.data);
        let userInfo = JSON.parse(evt.data)
        store.dispatch('test/login', { ...userInfo }).then(() => {
            router.push({ path: '/' })
            websocket.close()
        })
    };

    websocket.onerror = function (evt, e) {
        console.log('Error occured: ' + evt.data);
        console.log(e)
        qrCodeData.status = 'error'
        qrCodeData.errorInfo = '服务器连接错误,请查看网络连接'
    };
}

4.完成前端代码连接大米 我们给php加上swoole的扩展,完成后 新建server文件夹后,在文件夹新建run.php的文件 然后写下以下代码

<?php
//创建一个对象Swoole_Lite的对象实例
$swooleLite = new Swoole_Lite();

//类声明Swoole_Lite,其中有个构造函数__construct,实例化的同时就会运行此函数,实际上就是把需要运行的函数都放在了__construct
class Swoole_Lite
{
    public $server;
    public $table;
    public function __construct()
    {
        //实例化表格,参数 int : 最大行数 
        //$this->table实际上为了存储前端和swoole连接后的通道id
        $this->table = new swoole_table(1024);
        //设置表格字段  参数 (字段名:string , 字段类型:int、float、string , 长度:int)
        $this->table->column('id',$this->table::TYPE_INT,11);
        //创建表格
        $this->table->create();
        $this->server = new Swoole\WebSocket\Server("127.0.0.1", 9501);
        //设置心跳检测60秒时间内没有数据,自动关闭
        $this->server->set([
            'heartbeat_check_interval' => 30,
            'heartbeat_idle_time'      => 60,
        ]);
        $this->server->on('start', function ($server) {
            echo "Websocket Server is started at ws://127.0.0.1:9501\n";
        });

        $this->server->on('open', function (Swoole\WebSocket\Server $server, $request) {
            echo "server: handshake success with fd{$request->fd}\n";
        });

        $this->server->on('message', function (Swoole\WebSocket\Server $server, $frame)  {
            $data = json_decode($frame->data);
            //判断是否有重复websocket链接,关闭它 通过login来判断
            $this->disconnectRepeatWebSocket($data->login);
            $this->table->set($data->login,['id'=>$frame->fd]);
            // echo $table[$data->login];
            // echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
            // $server->push($frame->fd, "this is server");
        });
        $this->server->on('close', function ($ser, $fd) {
            foreach ($this->table as $key => $value) {
                if($value['id'] == $fd){
                    $this->table->del($key);
                }
            }
            $ser->push($fd,'close');
        });


        $this->server->on('request', function ($request, $response)  {
            $result = array('ret'=>'404','data'=>array('err_code'=>'1','ip'=>$request->server['remote_addr']),'msg'=>'没有可用的连接');
            $response->header('Content-Type', 'text/plain');
            $response->header('Charset', 'utf-8');
            var_dump($request->post);
            foreach ($this->table as $key => $value) {
                var_dump($key);
            }
            if ($this->server->isEstablished($this->table->get($request->post['login'],'id'))) {
                $userInfo = json_encode($request->post);
                $this->server->push($this->table->get($request->post['login'],'id'),$userInfo);
                $result['ret'] = '200';
                $result['data']['err_code'] = '0';
                $result['msg'] = '发送登录信息成功';
            }
            $response->end(json_encode($result));
    
        });
        $this->server->start();
    }

    function disconnectRepeatWebSocket($login){
        if($login){
            if($this->table->exist($login)){
                $this->server->isEstablished($table->get($login, 'id')) &&  $this->server->disconnect($table->get($login, 'id'));
                $this->table->del($login);
            }
        }
    }
    // //发送用户数据给web端,实现登录
    // function pushMessageToWeb($fd,$post_data){
    //     $this->server->push($fd,json_encode($post_data));
    // }
}

这段代码我也是从网上找来的,其中改了点地方,时间很长了,我也记不住了改动了哪里,我说下我的理解吧,也请大家指正, 首先我们先启动swoole服务, 使用cmd或者终端输入 php /路径/server/run.php

如下图 image.png 这就表示swoole服务器启动成功了。这样就完成了二维码扫码的功能实现。 哈哈,肯定不能这样结束,我刚刚只是告诉大家怎么使用swoole,并且贴上了代码 下面我还要给大家介绍下二维码登录时怎么实现的,以及解读下前端和swoole还有后端的代码,那我们就开始吧。swoole的run.php的代码分析我就写上面代码块中,一步步地分析,大家可以看下上面的代码注释,