近期有一需求:前端页面点击执行任务,实时显示后端执行情况,思考一波;发现WebSocket最适合做这件事。
效果
测试平www.baidu.com效果
点击连接建立《华盛顿明星报》连接
后端实现
所需软件包
后端主要借助姜戈频道实现窝连接,官网文档链接
这里想实现每个连接进来加入组进行广播,所以还需要引入频道-redis。
点
通道==2 .2 .0通道-redis==2.4.0引入
settings.py
INSTALLED _ APPS=[' django。贡献。admin ',' django.contrib.auth ',' django。内容类型',' django.contrib.sessions ',' django.contrib.messages ',' django.contrib.staticfiles ',' rest_framework.authtoken ',' rest_framework ',频道,]# Redis配置REDIS _ HOST=ENV _ dict。get(' REDIS _ HOST ',' 127。0 .0 .1’)REDIS _ PORT=ENV _ dict。get(' REDIS _ PORT ',6379)CHANNEL _ LAYERS={ ' default ' : { '后端: ' CHANNEL _ REDIS。核心。REDIS CHANNEL层',' CONFIG ' : { ' hosts ' :[(REDIS _ HOST,REDIS_PORT)],},}代码
应用程序/消费者
新建一个消费处理
实现:默认连接加入组,发送信息时的处理。
'从channels.generic.websocket导入web socketconsumerclass my consumer(web socketconsumer): def connect(self):“”每个任务作为一个频道默认进入对应任务执行频道自我。作业名=自我。作用域[' URL _ route '][' kwargs '][' job _ name ']self。job _ group _ name=' job _ % s ' % self。作业名async _ to _ sync(self。通道层。group _ add)(自我。作业组名,自我。channel _ name)self。accept()def disconnect(self,close _ code): async _ to _ sync(self。通道层。group _ discard)(自我。作业组名,自我。频道代码)类型处理def作业_消息(自我,事件): #默认发送收到信息自我。send(text _ data=event[' text '])app/routing。巴拉圭
《华盛顿明星报》类型路由
实现:ws/作业/作业名由我的消费者去处理。
来自从django进口消费者。URL从频道导入路径。路由导入协议类型路由器,来自通道的URLRouterfrom。sessions import sessionmiddlewarestkapapplication=protocol type router({ ' web socket ' : SessionMiddlewareStack(URLRouter([path(' ws/job/str : job _ name ',consumers .my consumer)])})应用程序/视图py .
在执行命令中获取求转发到消费通道,进行异步推送
使用异步推送异步到同步是因为在连接的时候采用的异步连接,所以推送必须采用异步推送。因为执行任务时间过长,启动触发运行时加入多线程,直接先返回好吧,后端运行任务从子流程导入Popen,PIPEimport threadingdef runPopen(作业): ' ' '执行命令,返回Popen ' ' '路径=操作系统。路径=路径。abpath(路径。连接(基目录,路径。pardir))脚本_路径=路径。abpath(路径。加入(路径,'运行。sh '))cmd=' sh % s % s ' %(脚本_路径,作业)返回Popen(cmd,shell=True,stdout=PIPE,stderr=PIPE)def runScript(job): channel _ layer=get _ channel _ layer()group _ name=' job _ % s ' % job Popen=runPopen(jobThread(target=runScript,args=(job,))run.start()返回HttpResponse(“ok”)应用程序/网址。巴拉圭
得到请求就能启动任务
urlpatterns=[.路径(' start_job/str:job ',StartJob.as_view())]前端实现
所需软件包
vue-native-websocket代码实现
插件/vuenativwebsocket。射流研究…
从“vue”导入某视频剪辑软件从“VueNativeSock”导入某视频剪辑软件./utils/socket/main。js ' export默认函数({ store }){ vue。使用(vuenativsock,' http://localhost:8000/ws/job ',{connectManually: true,});}nuxt.config.js
配置文件引入,这里我使用的是nuxt框架
plugins :[{ src : ' @/plugins/vuenativwebsocket。js ',***: false },],封装窝
导出默认值(connection_url,选项)={ //事件让事件=['消息','关闭','错误','打开'];//拷贝选项字典让opts=Object.assign({},option);//定义实例字典让实例={ //套接字实例socket: ' ',//是否连接状态is _ conncet: false,//具体连接方法connect :函数(){ if(connection _ URL){ let scheme=window。位置。协议===' https : '?WSS ' : ' ws ' connection _ URL=scheme ' ://' connection _ URL。split(' :/')[1];这个。socket=新的web socket(connection _ URL);这个。init event();}else{ console.log('wsurl為空');} }, //初始化事件initEvent:函数(){ for(让I=0;一。事件长度;i ){ this.addListener(事件[I]);} }, //判断事件addListener:函数(事件){ this.socket.addEventListener(事件),(e)={ switch(事件){ case ' open ' : this。is _ concet=true打破;案件'关闭' :这个。is _ conn cet=false打破;} opts[event]==' function '的类型opts[event](e);});}, //发送方法,失败则回调send:函数(数据,closeCallback){控制台。日志(' socket-'数据)if(this。插座。readystate=2){控制台。日志(' ws已经关闭');关闭回调closeCallback();}else{ this.socket.send(数据);} } };//调用连接方法实例。connect();返回实例;}index.vue
具体代码
x2Str方法,因为后端返回的是字节,格式b'xxx ',编写了方法对其进行转换。
模板按钮类型='primary' @click='runFunction '执行/el按钮el按钮类型=' primary ' @ click=' connectWebSock '显示/El-button div class=' SocketView ' span v-for=' Socketmessage中的I ' : key=' I ' { I } }/span/div/div/模板脚本从@/plugins/axios '导入r;从@/插件/插座'导入《华盛顿明星报》导出默认{ data() { return { webSocket: ' ',socketMessage: [,} },methods: { //打开连接的处理openSocket(e){如果(e .可信){ const h=this .$ createElement这个$notify({ title: '提示,message: h('i ',{ style: 'color: teal'},'已建立窝连接') });} }, //连接时的处理listenSocket(e){ if(e . data){ this。socketmessage。推(这个。x2str(e . data))},//连接webSocket connectWebSock(){ let wsuri=process。环境。后端_ URL '/ws/job/'这。选择此功能。webSocket=ws(wsuri,{ open: e=this.openSocket(e),message : e=this。listensocket(e),close : e=this。closesocket(e)})},//转码x2STr(str){ if(str){ let reg=new RegExp('?=^b').*(?='$)')让结果=str.replace(/(?\x[da-fA-F]{2}) /g,m=decodeURIComponent(m . replace(/ x/g,' % '))返回reg.exec(结果)[0] },//执行方法runFunction() { R.myRequest('GET ',' API/start _ job/' this。selectfunctions,{},{}).然后((响应)={ if(响应。hasown属性(' response '){ this .$message({ type: '错误,消息: '服务端返回错误,返回码:的回应。回应。状态});};if (response.data=='ok') { this .$message({ type: 'success ',message: '开始执行['这个。select functions ']' });} });} } }/脚本至此,实现前后端求转发到通讯。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。