flask+ajax实现轮询和长轮询

flask+ajax实现轮询和长轮询

轮询与连接简介

轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。
优点:后端程序编写比较容易。
缺点:请求中有大半是无用,浪费带宽和服务器资源。
实例:适于小型应用。


长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
优点:在无消息的情况下不会频繁的请求,耗费资源小。
缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。
实例:WebQQ、Hi网页版、Facebook IM。


长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。
优点:消息即时到达,不发无用请求;管理起来也相对方便。
缺点:服务器维护一个长连接会增加开销。
实例:Gmail聊天


Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。
优点:实现真正的即时通信,而不是伪即时。
缺点:客户端必须安装Flash插件;非HTTP协议,无法自动穿越防火墙。

轮询实例

from flask import Flask,render_template,request,jsonify

app = Flask(__name__)

USERS = {
    "1":{"name":"小黑","count":3},
    "2":{"name":"小白","count":2},
    "3":{"name":"小黄","count":1},
}


@app.route('/user/list')
def user_list():
    import time
    return render_template("user_list.html",users=USERS)


@app.route("/vote",methods=["POST"])
def vote():
    uid = request.form.get("uid")
    USERS[uid]["count"] += 1
    return "投票成功"


@app.route("/get/vote",methods=["GET"])
def get_vote():
    return jsonify(USERS)


if __name__ == '__main__':
    app.run()

template中的user_list.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>投票页面</title>

</head>
<body>
<ul id="useList">
    {% for key,val in users.items() %}
        <li uid="{{ key }}">{{ val.name }} ({{ val.count }}) </li>  {# 前端显示效果 #}
    {% endfor %}
</ul>

<script src="http://code.jquery.com/jquery-3.0.0.min.js"></script>
<script>
            $(function () {
            $('#userList').on('dblclick','li',function () {     // 给ul标签绑定事件委托
                var uid = $(this).attr('uid');      // 设置当前标签值为uid
                $.ajax({
                    url:'/vote',
                    type:'POST',
                    data:{uid:uid},
                    success:function (arg) {
                        console.log(arg);
                    }
                })
            });

        });


        /*
        获取投票信息
         */
        function get_vote() {
            $.ajax({
                url:'/get/vote',
                type:"GET",
                dataType:'JSON',
                success:function (arg) {
                    $('#userList').empty();     // 清空id=userList标签里的所有内容
                    $.each(arg,function (k,v) {     // 循环遍历    "1":{"name":"小黑","count":1}  键为前者,值为后者
                        var li = document.createElement('li');   // 创建li标签
                        li.setAttribute('uid',k);   // 设置当前的属性名与属性值
                        li.innerText = v.name + "(" + v.count + ')' ;   // 生成新的DOM
                        $('#userList').append(li);  // 添加该标签,加上下面的2秒执行get_vode,实现轮询
                    })

                }
            })
        }


        setInterval(get_vote,3000);   // 3秒
</script>


</body>
</html>

以下就是轮询的显示结果:

在这里插入图片描述

长轮询实例

关于上面的什么叫服务器接到请求后hold住连接,这里用一张很形象的图片来表示就是:
在这里插入图片描述

上图为我登录csdn博客中我的博文,但一直加载不出来,那么可能是网速问题,另一种就是服务器拦截了我的请求,直到有外来的帮助我才能完全显示页面,而假如没有这样的助力,那么最后,将会显示连接超时:

在这里插入图片描述

下面我们就用代码来实现这种机制:

from flask import Flask,render_template,request,jsonify,session
import uuid
import queue

app = Flask(__name__)
app.secret_key = 'qwertyuiopasdfghjkl'


USERS = {
    '1':{'name':'小黑','count':1},
    '2':{'name':'小白','count':0},
    '3':{'name':'小黄','count':0},
}

QUEQUE_DICT = {
    # 'xxxxxxxx':Queue()
}

@app.route('/user/list')
def user_list():
    user_uuid = str(uuid.uuid4())
    QUEQUE_DICT[user_uuid] = queue.Queue()	# 'xxxxxxxx':Queue()以uuid的形式创建Q,保证了唯一性

    session['current_user_uuid'] = user_uuid
    return render_template('user_list.html',users=USERS)

@app.route('/vote',methods=['POST'])
def vote():
    uid = request.form.get('uid')
    USERS[uid]['count'] += 1
    for q in QUEQUE_DICT.values():
        q.put(USERS)
    return "投票成功"


@app.route('/get/vote',methods=['GET'])
def get_vote():
    user_uuid = session['current_user_uuid']   # 构造session的请求上下文
    q = QUEQUE_DICT[user_uuid]   

    ret = {'status':True,'data':None}	# 构造一个json数据
    try:
        users = q.get(timeout=5)	# 设置获取时间为5
        ret['data'] = users
    except queue.Empty:
        ret['status'] = False

    return jsonify(ret)



if __name__ == '__main__':
    app.run(threaded=True)

这里有一个点是利用了队列来获取数据并构成长轮询。首先,队列有一个性质,不同浏览器发送请求,那么它将会为每一个请求创建一个Queue,这个时候就要就要看是否服务器有没有回响应,在这里,可以理解为服务器有没有将投票的数据给这些创建的Q,当要从里面取值时,先进入定时状态,也就是上面那张一直转圈的图,如果它里面没有数据,那么将在定时结束后,报出queue.Empty的异常,可以参考上图无法找到网页。但如果我们将其捕获,将其一起打包成json给前端,然后前端运用ajax的递归方式,就可以完成长轮询。


template里的user_list.html中:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        li{
            cursor: pointer;
        }
    </style>
</head>
<body>
    <ul id="userList">
        {% for key,val in users.items() %}
            <li uid="{{key}}">{{val.name}} ({{val.count}})</li>
        {% endfor %}
    </ul>

    <script src="https://cdn.bootcss.com/jquery/3.3.0/jquery.min.js"></script>
    <script>

        $(function () {
            $('#userList').on('click','li',function () {
                var uid = $(this).attr('uid');
                $.ajax({
                    url:'/vote',
                    type:'POST',
                    data:{uid:uid},
                    success:function (arg) {
                        console.log(arg);
                    }
                })
            });
            get_vote();	  // ajax版递归
        });

        /*
        获取投票信息
         */
        function get_vote() {
            $.ajax({
                url:'/get/vote',
                type:"GET",
                dataType:'JSON',
                success:function (arg) {
                    if(arg.status){
                        $('#userList').empty();
                            $.each(arg.data,function (k,v) {
                                var li = document.createElement('li');
                                li.setAttribute('uid',k);
                                li.innerText = v.name + "(" + v.count + ')' ;
                                $('#userList').append(li);
                            })
                    }
                    get_vote();

                }
            })
        }

    </script>
</body>
</html>

当项目开启后,我们可以从network中看到有着时间间隔的vote,而画红框的地方就是当前队列正在等待接收数据。

在这里插入图片描述

最终我们演示的效果如下:

在这里插入图片描述

我们可以发现长轮询的好处是省去了连接的次数,时效性非常高,所以对于QQ以及微信的登录来讲,都是有此机制的。

在这里插入图片描述

参考:

  1. https://www.cnblogs.com/gaoming7122/p/3524719.html
  2. http://www.cnblogs.com/wancy86/p/6234859.html
  3. https://blog.csdn.net/zhangskd/article/details/50194069
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
跨域问题是由于浏览器的同源策略导致的,所以我们需要在后端进行一些配置和处理来解决跨域问题。下面是解决跨域问题的步骤和详细代码: 步骤: 1. 安装 Flask-CORS 扩展 ``` pip install flask-cors ``` 2. 在 Flask 项目中使用 Flask-CORS 扩展 ```python from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) @app.route('/') def index(): return 'Hello, World!' ``` 3. 在前端使用 AJAX 发送跨域请求 ```javascript $.ajax({ url: 'http://localhost:5000/', type: 'GET', dataType: 'json', crossDomain: true, success: function(data) { console.log(data); }, error: function(xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); } }); ``` 详细代码: ```python from flask import Flask, jsonify from flask_cors import CORS app = Flask(__name__) CORS(app) @app.route('/') def index(): return jsonify({'message': 'Hello, World!'}) if __name__ == '__main__': app.run() ``` ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>AJAX 跨域请求示例</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> </head> <body> <script> $.ajax({ url: 'http://localhost:5000/', type: 'GET', dataType: 'json', crossDomain: true, success: function(data) { console.log(data); }, error: function(xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); } }); </script> </body> </html> ``` 注意:在开发中,为了安全起见,我们应该尽量减少跨域请求的使用,比如通过反向代理等方式来解决跨域问题。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值