前后端的交互问题
http的单项传递
最基本的协议,通常前段向后台发送,有get,post等等方法,现在前端上也有很多别的包可以用,axios等都可。但缺点在于它只能是前端向后端发起请求。
双向信息传递
要用到这个是因为近期项目中需要进行后台到前端的消息通知,也就是一个前后端的交互过程,在以往的过程中我们主要是利用http来进行前端到后端的请求,这样的交互方式是单项的,当我们需要后台传递消息给前端的时候,可以使用websocket。当然,暴力破解是永远可行的,所以技术上通常有三种方式:
短轮询
长轮询
websocket
暴力破解法:长短轮询
暴力破解永远是最熟悉的方法——客户端向服务端隔一段时间发送http请求回后台,间隔时间长短决定了轮询的次数,不过由于每次发送http请求的时候报文头可能都会比内容多,所以轮询会有浪费带宽的坏处,但简单的点在于它实现起来没有任何技术上的压力。
websocket:真正的双工实现
比起暴力破解,websocket更加智能和优雅🤯(当然,是在做出来的前提下,没做出来,各种奇怪的错误更让人自闭
websocket的机制
websocket首先会用http来进行连接,连接完成之后此项服务就会交给websocket来管理,之后就会建立长久的连接。
websocket的js原生实现
websocket的原生实现比较简单,这里用python来写后端代码,js来写前段代码(js用的es6的写法,这个是基于react框架,从中间截取出来)。
import asyncio
import websockets
# 接收客户端消息并处理,这里只是简单把客户端发来的返回回去
async def recv_msg(websocket):
while True:
recv_text = await websocket.recv()
response_text = f"your submit context: {recv_text}"
await websocket.send(response_text)
# 服务器端主逻辑
# websocket和path是该函数被回调时自动传过来的,不需要自己传
async def main_logic(websocket, path):
await recv_msg(websocket)
# 把ip换成自己本地的ip
start_server = websockets.serve(main_logic, 'localhost', 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
// 打开一个 web socket
const ws = new WebSocket("ws://localhost:5678");
// 连接建立后
ws.onopen=()=>
{
console.log("成功连接")
}
// 接收到服务器消息后,建立连接后会一直监听
ws.onmessage=(e)=>
{
const received_msg = e.data;
console.log("收到消息:"+received_msg);
}
//传递数据到服务器
ws.send("msg")
// 连接关闭后
ws.onclose =()=>
{
console.log("连接已关闭...");
}
这样的实现很简洁也很简单,对于前端来说,所有使用都在这上面做组合就可以了。
websocket的实现:基于socket.io
socket.io的官网地址:socket.io/
为什么要用socket.io的原因,孩子没娘说来话长,因为本身后端项目是基于python flask框架的,所以最初就定下要在flask框架下使用,而查询到flask框架包装好的websocket有:
flask sockets
flask socketio
flask sockets:对于websocket的简单包装,只能用在websocket阶段,如果不能使用websocket的情况就无法使用
flask socketio:这个是更完善的一个包括,在可以使用websocket的时候会使用websocket,不能使用的时候会采用长轮询。
所以最终决定用flaks socketio,然后前段采用socketio-client,而后台的使用可以参照网上的写法
下载的包是
npm install react-socket-io
,别问为什么,问就是不知道.
//使用方法
//导入,采用es6的方法
import io from 'socket.io-client'
//连接后台 http://ip:port/namespace
const socket = io("http://192.168.6.140:6888/test_conn")
//监听事件,这个server_response并不是固定的,他是和后端成对的
//如果前端监听 'server_response',他对应监听的消息就是后端socketio.emit('server_response','msg')
socket.on('server_response',(data)=>{
console.log(data)
//传送标记为event的消息,后端监听socketio.on('event',namespace='/test_conn')
socket.emit('event',"message")
})
踩坑记录----错误记录
-
Cannot read property 'sid' of undefined
-
前段可以接受到后台发送的sid信息,但是在socktio解析过程中报错无法得到sid的信息
-
//network中获取的第一个消息 0{"sid":"NWUwZWY4NzBiYjk1OQ==","upgrades":[],"pingInterval":44000,"pingTimeout":36000} //network的信息流 server----------------------------client ----0{sid,upgrades,pinginterval...}----> <------------------{40}----------------- ------------------>{40}----------------> ------------------>{40}---------------->
前段连接代码采用上面的引入import io from 'socket.io-client',不要用require('socket.io-client')
-
-
后台报错http1.1 400或者http1.1 404
-
后台socketio应该有
socketio = SocketIO(app, async_mode=async_mode,cors_allowed_origins='*')
-