基於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 CopyOnWriteArraySetwebSocketSet = 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; }
第一次在博客園寫隨寫,如有問題還望指正