1、开启一个服务
创建一个文件夹(dd-login),npm init -y初始化,安装ws依赖(npm i ws),启动服务(node app.js)
app.js
// 安装依赖:npm install ws
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 5000 }) // 启动 WebSocket 服务,监听 5000 端口
console.log('WebSocket 服务已启动,端口 5000')
wss.on('connection', ws => {
console.log('前端已连接')
// 监听前端发送的消息
ws.on('message', message => {
console.log(`收到前端消息: ${message}`)
const data = JSON.parse(message)
if (data.sessionId) {
console.log(`收到 sessionId:${data.sessionId}`)
// 模拟扫码结果推送,稍后一段时间发送登录结果
simulateLoginProcess(ws)
}
})
// 当前端断开连接
ws.on('close', () => {
console.log('前端断开连接')
})
ws.on('error', error => {
console.error('WebSocket 错误:', error)
})
})
// 模拟后台的登录流程
function simulateLoginProcess(ws) {
setTimeout(() => {
// 发送“pending”状态
ws.send(JSON.stringify({ status: 'pending', message: '等待用户扫码' }))
}, 1000)
// 模拟一个扫码完成后的状态变更
setTimeout(() => {
ws.send(JSON.stringify({ status: 'success', message: '扫码登录成功' }))
}, 5000) // 延迟 5 秒发送“成功”状态
}
2、模拟扫码登录
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>钉钉扫码登录 Demo</title>
<style>
#status {
margin: 20px 0;
font-size: 16px;
color: blue;
}
#qr-code {
width: 200px;
height: 200px;
margin: 20px auto;
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
</style>
</head>
<body>
<h1>钉钉扫码登录 Demo</h1>
<!-- 显示状态 -->
<div id="status">点击下方按钮以生成二维码进行登录</div>
<!-- 模拟二维码显示 -->
<div id="qr-code">二维码</div>
<!-- 按钮:触发扫码登录 -->
<button id="connect">生成登录二维码</button>
<script>
let socket
document.getElementById('connect').addEventListener('click', () => {
// 打开 WebSocket 连接
if (!socket || socket.readyState !== WebSocket.OPEN) {
connectWebSocket()
}
})
// 连接 WebSocket 的逻辑
function connectWebSocket() {
const sessionId = generateSessionId() // 模拟生成唯一的 sessionId
// 创建 WebSocket 连接
socket = new WebSocket('ws://192.168.1.37:5000')
// 当连接打开时发送数据
socket.onopen = () => {
console.log('WebSocket 连接已建立')
document.getElementById('status').innerText = '生成二维码中...'
// 向后端发送 sessionId
socket.send(JSON.stringify({ sessionId }))
}
// 接收后端推送的消息
socket.onmessage = event => {
const data = JSON.parse(event.data)
console.log('接收到消息:', data)
// 根据状态展示不同的信息
if (data.status === 'pending') {
document.getElementById('status').innerText = data.message
document.getElementById('qr-code').innerText = '等待扫码...'
} else if (data.status === 'success') {
document.getElementById('status').innerText = '登录成功!'
document.getElementById('qr-code').innerText = '已登录'
socket.close() // 登录成功后关闭连接
}
}
// 监听 WebSocket 错误
socket.onerror = error => {
console.error('WebSocket 错误:', error)
document.getElementById('status').innerText = '连接失败,请稍后重试!'
}
// 监听连接关闭
socket.onclose = () => {
console.log('WebSocket 连接已关闭')
}
}
// 模拟生成一个唯一的 sessionId
function generateSessionId() {
return 'session_' + Math.random().toString(36).substring(2, 15)
}
</script>
</body>
</html>
效果:
流程:
- 点击按钮打开弹框,此时调接口通过后端获取二维码图片,同时后端启动WebSocket服务
- 前端在拿到二维码图片后,一方面显示二维码在页面上,一方面初始化WebSocket实例,设置message事件,同时接口应该返回一个id,每次向后端发送消息时需要携带这个id
- 用户进行扫码时,后端识别到用户扫码操作,发送一个消息告诉前端,用户开始扫码了,前端可以显示用户扫码成功,请在手机上确认登录
- 用户在手机上点击确认登录后,后端发送一个消息给前端,一般通过一个状态码表示用户点击了确认登录了,前端在监听到这个状态码,就可以将页面显示为已登录状态,跳转到首页
- 在通信开始时实例化WebSocket,在通信结束后需要关闭WebSocket