跨域访问方法介绍(8)--使用 WebSocket

WebSocket 是 HTML5 开始提供的一种在单个 TCP 链接上进行全双工通信的协议;使用 ws://(非加密)和 wss://(加密)做为协议前缀。该协议不实行同源政策,只要服务器支持,就能够经过它进行跨源通讯。本文主要介绍使用 WebSocket 来实现跨域请求,文中所使用到的软件版本:Chrome 90.0.4430.2十二、Spring Boot 2.4.四、jdk1.8.0_181。javascript

一、WebSocket 简介

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,容许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只须要完成一次握手,二者之间就直接能够建立持久性的链接,并进行双向数据传输。在 WebSocket API 中,浏览器和服务器只须要作一个握手的动做,而后,浏览器和服务器之间就造成了一条快速通道。二者之间就直接能够数据互相传送。html

目前,不少网站都使用 Ajax 轮询来实现推送。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,而后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器须要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费不少的带宽等资源。html5

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,而且可以更实时地进行通信。java

 浏览器经过 WebSocket 对象向服务器发出创建 WebSocket 链接的请求,链接创建之后,客户端和服务器端就能够经过 TCP 链接直接交换数据。当获取 WebSocket 链接后,就能够经过 send() 方法来向服务器发送数据,并经过 onmessage 事件来接收服务器返回的数据。web

1.一、WebSocket 语法

let Socket = new WebSocket(url, [protocol]);

1.二、WebSocket 属性

属性 描述
WebSocket.readyState 只读属性 readyState 表示链接状态,能够是如下值:
0 - 表示链接还没有创建。
1 - 表示链接已创建,能够进行通讯。
2 - 表示链接正在进行关闭。
3 - 表示链接已经关闭或者链接不能打开。
WebSocket.bufferedAmount 只读属性 bufferedAmount 表示已被 send() 放入队列中正在等待传输,可是尚未发出的 UTF-8 文本字节数。

1.三、WebSocket 事件

事件 事件处理程序 描述
open WebSocket.onopen 链接创建时触发
message WebSocket.onmessage 客户端接收服务端数据时触发
error WebSocket.onerror 通讯发生错误时触发
close WebSocket.onclose 链接关闭时触发

1.四、WebSocket 实例

WebSocket 协议本质上是一个基于 TCP 的协议。为了创建 WebSocket 链接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和一般的 HTTP 请求不一样,包含了一些附加头信息,其中附加头信息"Upgrade: WebSocket"代表这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息而后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 链接就创建起来了,双方就能够经过这个链接通道自由的传递信息,而且这个链接会持续存在直到客户端或者服务器端的某一方主动的关闭链接。spring

二、WebSocket 实战

2.一、服务端实现(SpringBoot 版)

2.1.一、引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2.1.二、注入 ServerEndpointExporter

package com.abc.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2.1.三、WebSocket 实现类

package com.abc.demo.websocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketTest {
    private static Logger logger = LoggerFactory.getLogger(WebSocketTest.class);

    @OnOpen
    public void onOpen(Session session) {
        logger.info("有新链接加入:{}", session.getId());
        sendMessage(session);
    }

    @OnClose
    public void onClose(Session session) {
        logger.info("有一链接关闭:{}", session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("服务端收到客户端[{}]的消息:{}", session.getId(), message);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        logger.error("发生错误");
        error.printStackTrace();
    }

    private void sendMessage(Session session) {
        new Thread(() -> {
            try {
                for (int i = 0; i <= 10 && session.isOpen(); i++) {
                    session.getBasicRemote().sendText("服务端消息" + i);
                    Thread.sleep(1000 * 5);
                }
                if (session.isOpen()) {
                    session.getBasicRemote().sendText("服务端消息发送完毕。");
                }
                session.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }
}

2.二、客户端实现

websocket.html跨域

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>websocket测试</title>

<script type="text/javascript">
    let websocket = null;
    function initSocket() {
        if (window.WebSocket) {
            websocket = new WebSocket("ws://localhost:8081/websocket");
        } else {
            alert('你的浏览器不支持WebSocket');
            return;
        }
        
        websocket.onerror = function() {
            console.log('发生错误');
        };
    
        websocket.onopen = function(event) {
            console.log("创建链接");
        }
    
        websocket.onmessage = function(event) {
            document.getElementById('message').innerHTML += event.data + '<br/>';
        }
    
        websocket.onclose = function() {
            console.log("链接关闭");
        }
        
        //窗口关闭事件,关闭websocket链接。
        window.onbeforeunload = function() {
            websocket.close();
        }
    }
    initSocket();
    
    function closeWebSocket() {
        websocket.close();
    }

    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</head>
<body>
    <input id="text" type="text" />
    <button onclick="send()">Send</button>
    <button onclick="closeWebSocket()">Close</button>
    <div id="message"></div>
</body>

</html>

2.三、测试

把 websocket.html 放到 tomcat(端口:8080) 的 webapps\ROOT 下,并启动 SpringBoot 应用(端口:8081)。浏览器

 

参考:https://www.runoob.com/html/html5-websocket.htmltomcat

相关文章
相关标签/搜索