基於WebSocket實現簡單的掃碼登錄
WebSocket是一種在單個TCP連接上進行全雙工通信的協議。
WebSocket通信協議於2011年被IETF定為標准RFC 6455,並由RFC7936補充規范。WebSocket API也被W3C定為標准。
WebSocket使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在WebSocket API中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸。
因為是第一次接觸,所以畫了一個簡單的流程圖

上代碼
- 導包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
2.開啟spring支持
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@Component
@ServerEndpoint(value = "/websocket")
public class WebSocketWxLogin {
//用來存放每個連接對應的WebSocketWxLogin對象,適用於同時與多個客戶端通信
public static CopyOnWriteArraySet
webSocketSet = new CopyOnWriteArraySet
(); //其中Key為連接唯一標識 public static ConcurrentHashMap
webSocketMap = new ConcurrentHashMap
(); private Session session; /** * 建立連接成功調用的方法 */ @OnOpen public void onOpen(Session session)throws IOException { this.session = session; //我這里使用時間戳作為唯一id long l = System.currentTimeMillis(); String str = l+""; String sessionId = TripleDES.encode(str); webSocketSet.add(this); webSocketMap.put(sessionId,this); Map map = new HashMap(); map.put("code",400); map.put("msg","獲取成功!"); map.put("sessionId",sessionId); String s = JSONObject.toJSONString(map); session.getBasicRemote().sendText(s); } /** * 關閉連接調用的方法 */ @OnClose public void onClose(Session closeSession){ System.out.println(session); webSocketMap.remove(session); webSocketSet.remove(this); } /** * 向用戶推送消息 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } }
3.登錄接口
@PostMapping("login")
@ApiOperation(value = "掃碼登錄", notes = "掃碼登錄")
private Object login(String sessionId) {
Assert.notNull(sessionId,"缺少參數");
WebSocketWxLogin o1 = WebSocketWxLogin.webSocketMap.get(sessionId);
Assert.notNull(o1,"二維碼已過期");
Assert.notNull(getUser(),"未登錄!");
String token = getRequest().getSession().getId();
redisUtil.set(String.format(RedisParam.KEY_MOBILE_USER_LOGIN, token), getUser(), RedisParam.LOGIN_EXPIRE_TIME);
Map map = new HashMap();
map.put("code",401);
map.put("msg","登錄成功!");
map.put("token",token);
String s = JSONObject.toJSONString(map);
try {
o1.sendLogin(s);
}catch (Exception e){
return RespEntity.errorResp("登錄失敗!");
}
return RespEntity.successResp("登錄成功!",token);
}
4.JS代碼
<script type="text/javascript">
var websocket = new WebSocket("ws:127.0.0.1:8009/websocket");
//ws:服務器+端口/后端的端點
//接收到消息的回調方法
websocket.onmessage = function (event) {
console.log(event.data);
}
//連接關閉的回調方法
websocket.onclose = function () {
console.log("WebSocket連接關閉");
}
//監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,確保斷開時關閉連接
window.onbeforeunload = function () {
closeSocket();
}
//關閉WebSocket連接
function closeSocket() {
websocket.close();
}
</script>
如果線上使用了nginx,則需要在nginx配置文件里添加
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
這個寫在server里
location /ws/ {
proxy_pass http://127.0.0.1:8008/;
proxy_read_timeout 600;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
}
第一次在博客園寫隨寫,如有問題還望指正
