首页 > 其他分享 >WebSocket的简单应用

WebSocket的简单应用

时间:2024-02-23 10:24:45浏览次数:28  
标签:WebSocket get await token user 应用 简单 async event

Websocket简介

在HTML5中新增了WebSocket协议,它是在一个TCP连接上实现全双工通信的协议。

传统HTTP协议中,一次通信需要浏览器端主动发出请求后,由服务器端响应内容,建立的TCP连接断开,且无状态。而且必须是客户端主动请求后,服务器端才能响应,服务器端不能主动向浏览器端发送数据。每次浏览器端发起的请求包含较长头部,真正的请求数据就一小部分,这也会浪费很多带宽。

  • 较小的开销。协议层减小了包头,减小了开销
  • 更强的实时性。服务器端可以主动发数据给客户端,不需要等待客户端请求了,不需要客户端轮询了
  • 长连接。WebSocket需要创建TCP连接并维持它,有状态
  • 更好的二进制支持、压缩效果、扩展等

Websocket通信

前端不需要安装任何组件,因为HTML5支持,参考 https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

后端需要安装websockets,参考 https://websockets.readthedocs.io/en/stable/intro/index.html

简单应用

咱们要认识理解websocket通信,可以先发起简单的请求

前端部分

咱们只发起最简单的请求

这里发起最简单的请求,不做任何特殊处理

<template>
    <div>
        <h1>test</h1>
    </div>
</template>

<script>
export default {
    mounted() {
        if ('WebSocket' in window) {
            const ws = new WebSocket('ws://localhost:18888/1')
            // 当请求发起成功后的回调函数
            ws.onopen = (event) => {
                console.log('连接打开', event)
                ws.send('hello server')
            }
            // 当收到服务端消息时的回调函数
            ws.onmessage = (event) => {
                console.log('接收到消息', event.data)
            }
            // 当连接关闭时的回调函数
            ws.onclose = (event) => {
                console.log('连接关闭', event)
            }
            // 当连接出错时的回调函数
            ws.onerror = (event) => {
                console.log('连接出错', event)
            }
        } else {
            this.$message({
                showClose: true,
                message: '当前浏览器不支持websocket',
                type: 'error',
                center: true
            })
        }
    }
}
</script>

上面使用了四个回调函数,可以参考官网对事件的说明

后端部分

咱们后端采用的python

所以需要安装 websockets

pip install websockets

官网 https://websockets.readthedocs.io/en/stable/howto/quickstart.html

咱们这里做简单的接收和发送

参考官网代码修改

import asyncio
import websockets


async def hello(websocket, path):
    # 接收消息
    data = await websocket.recv()
    print(type(data), data)
    # 路径 可以根据路径不通做不同的处理
    print(path)
    # 发送消息
    await websocket.send("Hello!")


async def main():
    async with websockets.serve(hello, "localhost", 18888):
        await asyncio.Future()  # run forever


if __name__ == "__main__":
    asyncio.run(main())

以上是非常简单的一个websocket服务

接收后就发送字符串,然后连接就关闭了

当然,咱们既然发起使用的是websocket连接,如果只是一个来回就结束,那使用websocket就没什么意义

运行结果

前端

控制台中

网络请求

后端

<class 'str'> hello server
/1

在django中的应用

https://websockets.readthedocs.io/en/stable/howto/django.html

这里就以django中的认证来学习

这里的认证是使用jwt认证

关于jwt的相关配置

settings.py

INSTALLED_APPS = [
    ...
    'rest_framework_simplejwt',  # 注册应用,国际化,可选
    ...
]


REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    ...
}

from datetime import timedelta

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(hours=8),
}

在django中使用websocket

后端部分

import os
import django

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mm.settings')
django.setup(set_prefix = False)
# 由于需要调用django的配置,所以,上面四行必须在最上面

import asyncio
import websockets
import json
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken
from websockets.frames import CloseCode


async def handler(websocket, path):
    token = await websocket.recv()
    token = json.loads(token)
    if token['type'] == 'token':
        t = token['token']
        print(t)
        # 下面是校验认证的部分
        jwt_auth = JWTAuthentication()

        # 3.8版本之前的
        from asgiref.sync import sync_to_async

        # get_validated_token_async = sync_to_async(jwt_auth.get_validated_token)
        # payload = await get_validated_token_async(t)
        # get_user_async = sync_to_async(jwt_auth.get_user)
        # user = await get_user_async(payload)
        # print(type(user), user)

        # 3.9版本之后的
        try:
            payload = await asyncio.to_thread(jwt_auth.get_validated_token, t)
            user = await asyncio.to_thread(jwt_auth.get_user, payload)
            print(type(user), user)
        except InvalidToken as e:
            await websocket.close(CloseCode.INTERNAL_ERROR, e.detail.get("detail"))
            return
    else:
        await websocket.close(CloseCode.INTERNAL_ERROR, "非法请求")
        return

    # 校验通过后,就可以正常收发信息
    while True:
        print(path)
        data = await websocket.recv()
        print(data, type(data))
        # 这里使用close作为结束的标志
        if data == 'close':
            await websocket.close()
            return
        # 接收到消息,就返回消息
        await websocket.send(f"Hello {data}!")


async def main():
    async with websockets.serve(handler, "localhost", 18888):
        await asyncio.Future()  # run forever


if __name__ == "__main__":
    asyncio.run(main())

上面的基础逻辑

默认第一条消息就是传输token的,如果第一条消息没传输token,那就被视为非法请求,会直接断开连接

如果令牌有效,就会获取用户,然后就允许进行收发消息

前端部分

<template>
    <div>
        <h1>test</h1>
    </div>
</template>

<script>
export default {
    mounted() {
        if ('WebSocket' in window) {
            const ws = new WebSocket('ws://localhost:18888/1')
            ws.onopen = (event) => {
                console.log('连接打开', event)
                ws.send(
                    // 在第一条消息中装配token
                    JSON.stringify({
                        type: 'token',
                        token: window.localStorage.getItem('token')
                    })
                )
                ws.send('hello server1')
                ws.send('hello server2')
                ws.send('hello server3')
                ws.send('close')
            }
            ws.onmessage = (event) => {
                console.log('接收到消息', event.data)
            }
            ws.onclose = (event) => {
                console.log('连接关闭', event, event.reason)
            }
            ws.onerror = (event) => {
                console.log('连接出错', event)
            }
        } else {
            this.$message({
                showClose: true,
                message: '当前浏览器不支持websocket',
                type: 'error',
                center: true
            })
        }
    }
}
</script>

注意事项

websocketshandler 中需要将异步函数转换为同步函数

如果不转换,会报错

connection handler failed
Traceback (most recent call last):
...............
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

3.8版本之前

需要使用sync_to_async

from asgiref.sync import sync_to_async


# 需要将函数先转换为异步函数
get_validated_token_async = sync_to_async(jwt_auth.get_validated_token)
# 然后再用新函数调用参数
payload = await get_validated_token_async(t)
get_user_async = sync_to_async(jwt_auth.get_user)
user = await get_user_async(payload)
print(type(user), user)

也可以作为装饰器使用

from asgiref.sync import sync_to_async

@sync_to_async
def to_async(fun , *args):
	return fun(*args)


# 校验部分
jwt_auth = JWTAuthentication()
payload = await to_async(jwt_auth.get_validated_token, t)
user = await to_async(jwt_auth.get_user, payload)
print(type(user), user)

或者变形直接使用

from asgiref.sync import sync_to_async


payload = sync_to_async(jwt_auth.get_validated_token)(t)
user = sync_to_async(jwt_auth.get_user)(payload)
print(type(user), user)

3.9版本之后

import asyncio

payload = await asyncio.to_thread(jwt_auth.get_validated_token, t)
user = await asyncio.to_thread(jwt_auth.get_user, payload)
print(type(user), user)

标签:WebSocket,get,await,token,user,应用,简单,async,event
From: https://www.cnblogs.com/guangdelw/p/18028902

相关文章

  • 【行业方案】AI智能分析网关V4在校园消防安全场景中的应用
    校园作为学习、成长的重要场所,其安全问题至关重要。而消防安全更是校园安全的重中之重,它不仅关乎着师生的生命安全,也关系到学校正常的教学秩序。TSINGSEE青犀智慧校园烟火识别及预警方案融合了计算机视频图像分析技术、视频传输技术、智能预警、消息通知等技术,可对校园消防安全隐......
  • dremio cloner 简单试用
    以前简单介绍过dremiocloner工具,以下是一个简单试用dremio环境准备基于docker-compose,具体可以参考https://github.com/rongfengliang/dremio_cluster_docker-compose完成配置安装dremioclonerdremiocloner没有直接提供为一个pip包,需要自己安装clone代码......
  • 译:使用现代的 Node.js 构建简单的CLI工具
    原文地址:https://evertpot.com/node-changelog-cli-tool/作者:EvertPot发布时间:2023-02-13只使用Node.js的标准库,不安装任何外部依赖,写一个命令行工具。前言作者是多个开源项目的维护者,长久以来都是手动维护项目的变更日志(changelog)。下面是项目a12n-server的变更日......
  • 简单了解HTTP、Websocket和Netty
    前言伴随着网络的快速发展,网络通讯越来越重要,通讯的快捷、安全、方便影响着用户的体验。本文将探讨这些技术的原理、特点以及在实际应用中的应用场景。1.HTTTP(超文本传输协议)HTTP是一种传输超文本的协议,它是现代互联网通信的基础。其特点包括:简单性:HTTP使用简单的请求-响应模......
  • Web应用_6. Vue3
    title:(在线学习平台)link:(https://www.acwing.com/)cover:(https://cdn.acwing.com/media/activity/surface/log.png)Vue官网1配置环境1.1终端Linux和Mac上可以用自带的终端。Windows上推荐用powershell或者cmd。GitBash有些指令不兼容。1.2安装Nodejs安装地址1......
  • 车载打气泵应用方案设计流程
    便携车载打气泵主要使用在汽车轮胎充气及车胎检测上,是一个气压精度测量产品。打气泵方案则是通过马达运转工作而进行设计,利用芯片和气压传感器所做的一个智能化便携车载打气泵方案。下面就来说说关于一个打气泵应用解决方案的开发流程。打气泵方案确定开发需求......
  • 操作系统和应用
        1、监控程序的主要功能:程序的加载和运行2、在操作系统上运行的程序称为应用或应用程序3、调用操作系统的功能称为系统调用因为用机器员编写程序,在使用开关将程序输入这一过程非常麻烦,因此就有人开发出了操作系统的原型——仅具有加载和运行功能的监控程序。  ......
  • 缓存一梭子, 程序员的快乐就是如此简单
    缓存也是一把梭项目的标配,从业多年,有事无事set/getCache来一梭子。夜深人静的时候,头脑里冷不丁会出现一些问题,我竟一时无法自圆其说。已经有cpu多级缓存、操作系统pagecache,那为什么还需要定义应用缓存?应用的多个副本缓存了同一份数据库数据,怎么保证这些多副本的缓存一致性?......
  • BOSHIDA DC电源模块在工业自动化中的应用案例分析
    BOSHIDADC电源模块在工业自动化中的应用案例分析BOSHIDADC电源模块在工业自动化中有很多应用案例,以下是其中几个典型的例子:1.机器人控制系统:机器人在工业自动化中有着重要的作用,而机器人的控制系统需要稳定可靠的电源供应。DC电源模块可以提供稳定的直流电源,满足机器人控制......
  • 【专题】2023年全球移动应用(非游戏)营销趋势白皮书报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=35180原文出处:拓端数据部落公众号随着国内政策调整,移动APP业务前景充满不确定性,但这也为出海应用带来了新机遇。2023年,AI和短剧应用的崛起为出海行业注入了信心。随着用户需求增长和技术进步,这两个领域有望在2024年迎来更大发展。阅读原文,获取专......