3.aiohttp中websocket的使用
1.什么是websocket对于传统的web开发而言,是前台发送请求,后端接口返回对应的数据。但是在爬虫网页项目中当用户在页面上发送爬取请求之后,这个时候如果是传统的ajax请求,则前台就会阻塞,并且我们需要后台实时的通知用户现在爬虫的爬取进度。为了完成这一系列的交互功能,我们就需要使用websocket。websocket本质上就是一种协议,这种协议可以允许服务端主动给客户端客户端推送数据,在与
目录
1.什么是websocket
对于传统的web开发而言,是前台发送请求,后端接口返回对应的数据。但是在爬虫网页项目中当用户在页面上发送爬取请求之后,这个时候如果是传统的ajax请求,则前台就会阻塞,并且我们需要后台实时的通知用户现在爬虫的爬取进度。为了完成这一系列的交互功能,我们就需要使用websocket。websocket本质上就是一种协议,这种协议可以允许服务端主动给客户端客户端推送数据,在与vue相结合之后可以实现实时的数据刷新与展示效果。
2.如何在aiohttp中使用websocket
aiohttp中自带了websocket,并且是异步实现。这就意味着可以实时向客户端推送最新的数据。在flask中如何想实现这样功能的websocket则需要使用celery任务队列来完成。对于aiohttp来说使用websocket只需要以下的代码
async def websocket_handler(request):
ws = web.WebSocketResponse()
await ws.prepare(request) # 等待websocket连接
async for msg in ws:
if msg.type == aiohttp.WSMsgType.TEXT:
if msg.data == 'close':
await ws.close()
else:
await ws.send_str(msg.data + '/answer')
elif msg.type == aiohttp.WSMsgType.ERROR:
print('ws connection closed with exception %s' %
ws.exception())
print('websocket connection closed')
return ws
也可以使用ws.send_json来直接向前台发送json格式的数据,需要注意的是如果含有中文的话需要将ensure_ascii设置为False
3.如何在vue中使用websocket
在vue中使用websocket可以使用原始的websocket,也可以使用websocketio,这里我后台使用的是aiohttp的websocket,所以在vue中直接使用的是websocket。为了便于websocket的统一管理,我将websocket放到了vuex中进行全局管理,具体的大致芦逻辑如下,以登陆电影界面为例:
(1) 在用户登陆之后默认连接所有的websocket,用户退出之后默认断开所有的websocket(因为此时可能还有其他的爬虫任务正在后台运行,需要后台实时向前台推送数据)
(2)在进入需要使用websocket的界面之前检查websocket的状态,如果没有连接则连接之
(3)在离开需要使用websocket的界面之后,检查对应的websocket的任务状态,如果没有任务在运行则断开
(4)综上,将websocket放在vuex中进行管理,具体代码如下
store中的代码
import restFulUrl from "@/utils/config"
const state = {
// movie websocket的连接状态管理
movieSocket: {
socket: '', // websocket连接
taskState:'' // 当前websocket的任务状态
},
}
const mutations = {
CONNECT_Movie: (state) =>{
state.movieSocket.socket = new WebSocket(restFulUrl().replace("http", "ws") + "/search_movie") // 连接websocket
},
DisConnect_Movie: (state) =>{
state.movieSocket.socket.send(JSON.stringify({'state': 'close'}))
state.movieSocket.socket = '' // 断开连接
state.movieSocket.taskState = '' // 还原任务状态
},
Set_Movie_Task_State: (state, taskState)=>{
state.movieSocket.taskState = taskState // 设置任务状态
}
}
const actions = {
connectMovie({commit}){
commit('CONNECT_Movie')
},
disconnectMovie({commit}){
commit('DisConnect_Movie')
},
setMovieTaskState({commit}, taskState){
commit('Set_Movie_Task_State', taskState)
}
}
export default
{
namespaced: true,
state,
actions,
mutations
}
permission.js
router.afterEach((to, from) => {
// finish progress bar
switch (from.path.split('/').pop()) {
case 'movie':
// 如果是电影界面
if (!store.getters.movieSocket.taskState) {
// 如果没有任务正在执行则断开连接
store.dispatch('socket/disconnectMovie').then(()=>{
})
}
break
}
NProgress.done()
})
index.js
{
path: 'movie',
name: 'Movie',
beforeEnter(to, from, next) {
if (!store.getters.movieSocket.socket) {
// 如果没有建立websocket连接则建立连接
connect.connectMovieSocket()
}
next()
},
component: () => import('@/views/movie/index'),
meta: {title: '电影', icon: 'el-icon-film'}
},
movie/index.vue
created() {
this.$store.getters.movieSocket.socket.onmessage = (response) => {
this.responseData = JSON.parse(response.data)
this.code = this.responseData.code
switch (this.code) {
case 200:
this.buttonContent = '日志查看'
this.$store.getters.movieSocket.taskState = ''
this.searchResult = this.responseData.data.result
this.total = this.responseData.data.total
this.loadText = "正在从数据库中获取结果"
this.loading = false
break
case 204:
this.$store.getters.movieSocket.taskState = 1 // 更新websocket的任务状态
this.loading = false
this.buttonContent = '当前任务' // 切换按钮的text
this.currentLog = this.responseData.data.result.join("\n") // 显示当前爬虫日志
this.log = this.currentLog
// this.ref$['taskButton'].text = '任务查看'
// this.loadText = "正在从网页重新爬取结果"
// this.loading ? '' : this.loading = true
break
case 500:
this.loading = false
this.$message({
message: "请求出错",
type: "danger"
})
break
}
}
this.getList()
},
这样在每次进入电影界面之前就会自动连接websocket.效果如下:
详细的代码和注册可以查看我的github: https://github.com/JustKeepSilence/DownLoad,欢迎大家交流和讨论~
更多推荐
所有评论(0)