专栏首页代码拾遗SpringMVC 教程 - SockJS

SpringMVC 教程 - SockJS

在公网上,一些代理可能会阻止WebSocket交互,有的代理会配置不传递Upgrade头,有的会断开空闲的连接。 可以使用仿真来解决这个问题,例如:首先尝试使用WebSocket连接,失败后是用基于HTTP的技术,模仿WebSocket的交互,并且暴露相同的API。 Spring使用了SockJS协议来支持。

概览

SockJS的目标是使用WebSocket的API,当WebSocket不可用的时候使用非WebSocket的选项,而无需修改代码。 SockJS包括:

  • SockJS 协议
  • SockJS JavaScript 客户端
  • SockJS服务端实现,spring-wesocket 模块中实现了这个。
  • spring-websocket 提供了SockJS的Java客户端

SockJS是设计在浏览器中使用的。查询SockJS Client来查看SockJS支持的浏览器。支持三种方式传输数据:WebSocket,HTTP Streaming,HTTP长轮询。 当SockJS发送 GET /info 请求的时候,服务端需要决定使用哪种传输格式,首先会检查WebSocket,如果不行则使用HTTP Streaming,如果还是不行就使用HTTP的长轮询。

URL 的格式如下:

http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}
  • {server-id} 集群中路由请求的时候使用
  • {session-id} SockJS相关的session
  • {transport} 使用的transport类型,例如,WebSocket

WebSocket 只需要一个HTTP请求用来握手,剩下的都只需要单个链接即可完成交互 HTTP 需要更多的请求。例如:Ajax/XHR streaming 依赖于一个长时间运行的server到client的请求。长轮询则每次都会进行请求查询。 SockJS简化了消息帧,例如:server发送 o 表示(open),如果25秒没有消息发送 h 表示 heartbeat 心跳。c 表示close等。

打开SockJS

Java配置:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler(), "/myHandler").withSockJS();
    }

    @Bean
    public WebSocketHandler myHandler() {
        return new MyHandler();
    }

}

XML 配置:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:websocket="http://www.springframework.org/schema/websocket"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/websocket
        http://www.springframework.org/schema/websocket/spring-websocket.xsd">

    <websocket:handlers>
        <websocket:mapping path="/myHandler" handler="myHandler"/>
        <websocket:sockjs/>
    </websocket:handlers>

    <bean id="myHandler" class="org.springframework.samples.MyHandler"/>

</beans>

在浏览器中直接使用socket-client

如果使用了iframe,那么需要在http 响应头设置 X-Frame-Options为:SAMEORIGIN,ALLOW-FROM。 Java 配置:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/portfolio").withSockJS()
                .setClientLibraryUrl("http://localhost:8080/myapp/js/sockjs-client.js");
    }

    // ...

}
心跳

SockJS协议要求服务端发送心跳信息,防止代理挂起链接。SockJS配置heartbeatTime来设置心跳的频率。没有其他消息发送的时候,默认心跳时间为25秒。25秒的设置是依据IETF recommendation的推荐设置。 Spring SockJS 同样也可以配置TaskScheduler管理心跳任务。

客户端断开连接

HTTP Streaming和长轮询模式要求请求比之前持续的时间更长。在Servlet容器中,Servlet 3 异步特性可以支持这个功能。但是Servlet API在客户端断开连接的时候并没有发送消息。当像一个已经关闭的链接写入响应的时候,Servlet 容器会抛出异常。

SockJS 跨域

SockJS使用CORS来支持跨域问题。CORS头是自动加的,所以如果已经在SpringMVC配置了的话就可以完全跳过这部分。 SockJS 支持的头:

  • Access-Control-Allow-Origin:请求头的Origin
  • Access-Control-Allow-Credentials: 一直是true
  • Access-Control-Request-Headers:来自请求头的相同的头
  • Access-Control-Allow-Methods:支持协议的方法
  • Access-Control-Max-Age: 31536000(一年)
SockJs 客户端

SockJS提供了Java客户端可以不使用浏览器就可以访问服务器。这样在公网上两台服务器双向通信的时候非常的方便。例如代理可能会组织使用WebSocket。同样,SockJS的Java客户端也很适合做测试,例如测试同时访问最多用户数。 SockJS的Java客户端支持websocket,xhr-streaming,xhr-polling传输协议。 示例如下:

List<Transport> transports = new ArrayList<>(2);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
transports.add(new RestTemplateXhrTransport());

SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.doHandshake(new MyWebSocketHandler(), "ws://example.com:8080/sockjs");

配置:

@Configuration
public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/sockjs").withSockJS()
            .setStreamBytesLimit(512 * 1024)
            .setHttpMessageCacheSize(1000)
            .setDisconnectDelay(30 * 1000);
    }

    // ...
}

本文分享自微信公众号 - 代码拾遗(gh_8f61e8bcb1b1)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SpringMVC 教程 - WebSocket

    WebSocket提供了在客户端和服务端通过单一TCP连接建立全双工双向通信的通道。它是和HTTP不同的TCP协议,但是却建立在HTTP之上,使用80,443端...

    代码拾遗
  • ​SpringMVC 教程 - Handler Method

    由注解@RequestMapping注解修饰的处理请求的函数的签名非常的灵活,可以使用controller函数支持的一系列参数和返回值。

    代码拾遗
  • Spring Boot 2.0 教程 - 配置详解

    Spring Boot 可以通过properties文件,YAML文件,环境变量和命令行参数进行配置。属性值可以通过,@Value注解,Environment...

    代码拾遗
  • Newbe.Mahua 2.4 恢复 QQLight

    QQLight 由于众所周知的原因已经升级到了 3.X 的SDK,旧版本全部失效,现在我们更新了版本以重新支持。

    newbe36524
  • 配置ssh免密登陆

    声明:本文为原创,作者为 对弈,转载时请保留本声明及附带文章链接:http://www.duiyi.xyz/c%e5%ae%9e%e7%8e%b0%e9%9b%...

    对弈
  • SSH反向连接及Autossh

    最近因为工作需要,要给生产环境的MySQL在云上搞灾备实例【 专有网络的VPC主机,×××专线太贵,走公网又不安全,暂时准备用ssh隧道跑着试试看】

    二狗不要跑
  • 2018-04-30项目遇到的问题及处理方法

    用户1733354
  • ssh默认端口配置

    ssh有两层含义: 一是SSH(Secure Shell),由 IETF 的网络小组(Network Working Group)所制定的应用层安全外壳协议,...

    Dabelv
  • gradlew在Travis CI没可执行权限 permission denied

    Ryan-Miao

扫码关注云+社区

领取腾讯云代金券