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)

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

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏沈唁志

PHP进阶之利用Swoole实现一个简单的WebSocket多人聊天室

其实这个聊天室的DEMO我早都发到Github上了,之前学习Swoole的时候就已经练过手了

79220
来自专栏大魏分享(微信公众号:david-share)

Oracle11g RAC双NFS仲裁容错方案

说明: 整理文档时发现自己在2010年写的一个RAC容灾方案,觉得有一些用,分享出来。当时为了验证此方案,做了很多PoC。方案相对比较复杂,但是也提供了一种思路...

55890
来自专栏Netkiller

PHP高级编程之守护进程

PHP高级编程之守护进程 摘要 2014-09-01 发表 2015-08-31 更新 2015-10-20 更新,增加优雅重启 ---- 目录 1. 什么是守...

34840
来自专栏北京马哥教育

DNS从入门到管理(一)

DNS概述 DNS(Domain Name System,域名系统),域名和IP地址相互映射的一个分布式数据库,通过主机名,最终得到该主机名对应的IP地址的过程...

68260
来自专栏小狼的世界

Log stash学习笔记(一)

Logstash是一款开源的数据收集引擎,具备实时管道处理能力。简单来说,logstash作为数据源与数据存储分析工具之间的桥梁,结合 ElasticSearc...

15030
来自专栏静默虚空的博客

Elastic 技术栈之 Filebeat

Elastic 技术栈之 Filebeat 简介 Beats 是安装在服务器上的数据中转代理。 Beats 可以将数据直接传输到 Elasticsearch 或...

52670
来自专栏白驹过隙

Socket编程回顾,一个最简单服务器程序

23230
来自专栏向治洪

认识Kubernates(K8S)

在后端开发中,在介绍Jenkins的可伸缩部署方式上,主要有两种方式:一种是基于Docker(或者docker-swarm 集群)的部署方式,另外一种是基于ku...

85080
来自专栏calvin

jira webhook 事件触发并程序代码调用jenkins接口触发构建操作

开发管理工具触发站点构建事件,事件处理中需要调用Jenkins接口开始构建动作。 我的应用场景: 使用jira作为管理工具,在jira中创建自定义的工作流来...

86130
来自专栏Golang语言社区

【Go 语言社区】一个WebSocket的简单Echo例子

一个WebSocket的简单Echo例子:例子代码来自:http://www.websocket.org/echo.html 使用一个文本编辑器,把下面代码复制...

31470

扫码关注云+社区

领取腾讯云代金券