文档章节

tomcat 7下spring 4.x mvc集成websocket以及sockjs完全参考指南(含nginx/https支持)

robinjiang
 robinjiang
发布于 2017/05/12 21:34
字数 3210
阅读 1406
收藏 4

之所以sockjs会存在,说得不好听点,就是因为微软是个流氓,现在使用windows 7的系统仍然有近半,而windows 7默认自带的是ie 8,有些会自动更新到ie 9,但是大部分非IT用户其实都不愿意或者不会升级(通常我们做IT的认为很简单的事情,在其他行业的人来看,那就是天书,不要觉得不可能,现实已如此)。

现在言归正传,这里完整的讲下在spring 4.x集成sockjs,以及运行在tomcat 7下时的一些额外注意事项。

spring websocket依赖jar:

复制代码

<dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.1</version>
            <scope>provided</scope> <!-- 注意,scope必须为provided,否则runtime会冲突,如果使用tomcat 8,还需要将TOMCAT_HOME/lib下的javax.websocket-api.jar一并删除 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>4.2.8.RELEASE</version>
        </dependency>

复制代码

除非使用STOMP协议,否则不需要依赖spring-messaging。

spring通过两种模式支持websocket,一种是通过原生websocket规范的ws://协议访问(个人认为如果确定只用标准websocket访问,还不如tomcat升级到8.x(tomcat 8原生支持JSR 356注解),spring的大量封装毕竟增加了不少额外负载);另一种则是通过sockjs(也就是js)访问,两者目前暂时无法做到兼容。

先完整说明第一种:

1、搭建spring mvc环境,这一点假设读者已知;

2、pom.xml中引入上面两个jar包;

3、spring支持websocket总共分为四个小步骤,handler、interceptor、config、web.xml,基本上可以认为spring mvc的翻版。

3.1、创建WebSocketHandler,spring支持两种方式,一种是实现org.springframework.web.socket.WebSocketHandler接口,另外一种则是继承TextWebSocketHandler或BinaryWebSocketHandler(现在大部分模板式框架或者插件通常都是在提供了API的基础上提供了抽象类,把一些能统一的工作提前预置了,以便应用只需要关心业务,我们自己公司的中间件框架很多也是用这个模式实现了)。

/**
 * 
 */
package com.ld.net.spider.demo.ws;

/**
 * @author zhjh256@163.com
 * {@link} http://www.cnblogs.com/zhjh256
 */
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

public class DemoWSHandler implements WebSocketHandler {  
  
    @Override  
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {  
        System.out.println("connect to the websocket success......");  
        session.sendMessage(new TextMessage("Server:connected OK!"));  
    }  
  
    @Override  
    public void handleMessage(WebSocketSession wss, WebSocketMessage<?> wsm) throws Exception {  
        TextMessage returnMessage = new TextMessage(wsm.getPayload()  
                + " received at server");  
        System.out.println(wss.getHandshakeHeaders().getFirst("Cookie"));  
        wss.sendMessage(returnMessage);  
    }  
  
    @Override
    public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception {  
        if(wss.isOpen()){  
            wss.close();  
        }  
       System.out.println("websocket connection closed......");  
    }  
  
    @Override  
    public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception {  
        System.out.println("websocket connection closed......");  
    }  
  
    @Override  
    public boolean supportsPartialMessages() {  
        return false;  
    }
}

3.2、创建拦截器

/**
 * 
 */
package com.ld.net.spider.demo.ws;

import java.util.Map;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

/**
 * @author zhjh256@163.com 
 * {@link} http://www.cnblogs.com/zhjh256
 */
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {

        // 解决The extension [x-webkit-deflate-frame] is not supported问题
        if (request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
            request.getHeaders().set("Sec-WebSocket-Extensions",
                    "permessage-deflate");
        }

        System.out.println("Before Handshake");
        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request,
            ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception ex) {
        System.out.println("After Handshake");
        super.afterHandshake(request, response, wsHandler, ex);
    }
}

3.3、bean配置

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:util="http://www.springframework.org/schema/util"   
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/mongo       
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd   
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://activemq.apache.org/schema/core 
http://activemq.apache.org/schema/core/activemq-core.xsd
http://www.springframework.org/schema/jms 
http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
    <websocket:handlers allowed-origins="*">
        <websocket:mapping path="/springws/websocket.ws" handler="demoWSHandler"/>
         <websocket:handshake-interceptors>
            <bean class="com.ld.net.spider.demo.ws.HandshakeInterceptor"/>
        </websocket:handshake-interceptors>
    </websocket:handlers>

    <bean id="demoWSHandler" class="com.ld.net.spider.demo.ws.DemoWSHandler"/>

上述需要注意的是,1、spring javadoc的说明是默认情况下,允许所有来源访问,但我们跑下来发现不配置allowed-origins的话总是报403错误。

2、sockjs是不允许有后缀的,否则将无法匹配,后面会专门讲到。

3.4、web.xml配置

在web.xml中增加*.ws映射即可(如果原来不是/*的话),如下:

<servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>*.ws</url-pattern>
    </servlet-mapping>

上述配置完成之后,就可以通过标准的websocket接口进行访问了,如下所示。

4、websocket客户端

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Web Socket JavaScript Echo Client</title>
  <script src="http://cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>
  <script language="javascript" type="text/javascript">
    var echo_websocket;
    function init() {
      output = document.getElementById("output");
    }

    function send_echo() {
      var wsUri = "ws://localhost:28080/springws/websocket.ws";
      writeToScreen("Connecting to " + wsUri);
      echo_websocket = new WebSocket(wsUri);
      echo_websocket.onopen = function (evt) {
        writeToScreen("Connected !");
        doSend(textID.value);
      };
      echo_websocket.onmessage = function (evt) {
        writeToScreen("Received message: " + evt.data);
        echo_websocket.close();
      };
      echo_websocket.onerror = function (evt) {
        writeToScreen('<span style="color: red;">ERROR:</span> '
          + evt.data);
        echo_websocket.close();
      };
    }
    function doSend(message) {
      echo_websocket.send(message);
      writeToScreen("Sent message: " + message);
    }
    function writeToScreen(message) {
      var pre = document.createElement("p");
      pre.style.wordWrap = "break-word";
      pre.innerHTML = message;
      output.appendChild(pre);
    }
    window.addEventListener("load", init, false);
  </script>
</head>
<body>
<h1>Echo Server</h1>
<div style="text-align: left;">
  <form action="">
    <input onclick="send_echo()" value="发送socket请求" type="button">
    <input id="textID" name="message" value="Hello World, Web Sockets" type="text">
    <br>
  </form>
</div>
<div id="output"></div>
</body>
</html>

上述前后端均配置完成后,基于标准websocket api的搭建就完成了,试试吧。。

现在再来看下sockjs的配置。

spring对sockjs和websocket支持的差别在于配置,web.xml,以及客户端,服务实现无差别。

3.3需要调整为如下:

<websocket:handlers>
        <websocket:mapping path="/springws/websocket" handler="demoWSHandler"/>
         <websocket:handshake-interceptors>
            <bean class="com.ld.net.spider.demo.ws.HandshakeInterceptor"/>
        </websocket:handshake-interceptors>
        <websocket:sockjs/>
    </websocket:handlers>

    <bean id="demoWSHandler" class="com.ld.net.spider.demo.ws.DemoWSHandler"/>

3.4 一定要有到/xxx/*的映射,简单的可以直接/*,如下所示:

<servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

上述配置完成后,就sockjs直接性的支持而言,就可以没有问题了。

客户端则为如下:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Web Socket JavaScript Echo Client</title>
  <script src="http://cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>
  <script language="javascript" type="text/javascript">
    var echo_websocket;
    function init() {
      output = document.getElementById("output");
    }
    function send_echo() {
      echo_websocket = new SockJS("http://localhost:28080/springws/websocket") ;   //初始化 websocket

      echo_websocket.onopen = function () {
        console.log('Info: connection opened.');
      };

      echo_websocket.onmessage = function (event) {
        console.log('Received: ' + event.data); //处理服务端返回消息
      };

      echo_websocket.onclose = function (event) {
        console.log('Info: connection closed.');
        console.log(event);
      };

      ws.send("abcabc");
    }
    
    function doSend(message) {
      echo_websocket.send(message);
      writeToScreen("Sent message: " + message);
    }
    function writeToScreen(message) {
      var pre = document.createElement("p");
      pre.style.wordWrap = "break-word";
      pre.innerHTML = message;
      output.appendChild(pre);
    }
    window.addEventListener("load", init, false);
  </script>
</head>
<body>
<h1>Echo Server</h1>
<div style="text-align: left;">
  <form action="">
    <input onclick="send_echo()" value="send websocket request" type="button">
    <input id="textID" name="message" value="Hello world, Web Sockets" type="text">
    <br>
  </form>
</div>
<div id="output"></div>
</body>
</html>

 

上述配置完成后,如果访问没有CORS异常的话,基于sockjs的websocket就完成了。试试吧。。。

典型错误及原因、解决方法如下:

Error during WebSocket handshake: Unexpected response code: 404
检查web.xml servlet-mapping包含了到websocket路径的映射,比如如果请求不含后缀,就必须包含/*的映射

 

WebSocket connection to 'ws://localhost:8080/springwebsocket/websocket' failed: Error during WebSocket handshake: Unexpected response code: 403
<websocket:handlers allowed-origins="*">,javadoc说明默认代表所有站点,实际好像并不是,所以需要配置*

 

sockjs启用
启用sockjs后,直接用websocket协议访问会报
html5ws.html:15 WebSocket connection to 'ws://localhost:28080/springws/websocket.ws' failed: Error during WebSocket handshake: Unexpected response code: 200

 

直接改为sockjs后,会报
XMLHttpRequest cannot load http://localhost:28080/springws/websocket.ws/info?t=1478758042205. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 404.
需要在web.xml中配置CORS过滤(注意,如果apache有自带的类库,建议直接使用,不要随意听信网上的自己实现过滤器的搞法,这些库一天的运行次数可能就比自己写的运行到淘汰还多,所以几乎常见的问题都不可能遗漏):

使用sockjs还有一点需要注意的是:
因为sockjs会自动在url之后增加/info?t=XXXX等路径,如果这里url-pattern拦截类似于*.ws这种带后缀的就找不到映射,比如想通过sockjs访问地址/springws/websocket.ws,但是sockjs框架会先访问/springws/websocket.ws/info这个地址,但是这个地址又不可被spring框架识别,所以导致不可用。

到此为止,tomcat 7下spring 4.x mvc集成websocket以及sockjs的配置就全部介绍完成。

今天看群里一个消息的时候,提到HA时一台服务器挂掉的问题,这就回到socket的思路了,客户端也得加上个定时的心跳逻辑,万一某台服务器挂了或者断网可以failover并自动重新建立连接。在我们的业务中,可靠性这一点是很关键的。

默认情况下,ws://走的时候http协议,即使主页面是通过https访问,此时会出现连接时异常"[blocked] The page at 'https://localhost:8443/endpoint-wss/index.jsp' was loaded over HTTPS, but ran insecure content from 'ws://localhost:8080/endpoint-wss/websocket': this content should also be loaded over HTTPS.Uncaught SecurityError: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.",此时需要使用如下连接:

websocket:wss://localhost:8080/endpoint-wss/websocket

sockJS:https://localhost:8080/endpoint-wss/socketJS

 

配置nginx支持websocket,默认情况下,nginx不支持自动升级至websocket协议,否则js中会出现连接时异常"Error during WebSocket handshake: Unexpected response code: 400",需在恰当的位置加上如下设置:

server {
    listen 8020;
    location / {
        proxy_pass http://websocket;
        proxy_set_header Host $host:8020; #注意, 原host必须配置, 否则传递给后台的值是websocket,端口如果没有输入的话会是80, 这会导致连接失败
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
}
upstream websocket {
    server 192.168.100.10:8081;
}

经上述调整后,websocket就可以同时支持通过nginx代理的https协议,结合MQ机制,可以做到B端实时推送、B端/C端实时通信。
nginx的https(自动跳转http->https)+nginx+websocket的完整配置可参考http://www.cnblogs.com/zhjh256/p/6262620.html。

===============================================================

补充:

ie下使用sockjs,后台Tomcat会报错:

java.io.IOException: APR error: -730054
	at org.apache.coyote.http11.InternalAprOutputBuffer.writeToSocket(InternalAprOutputBuffer.java:292) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.InternalAprOutputBuffer.writeToSocket(InternalAprOutputBuffer.java:245) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:214) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.AbstractOutputBuffer.flush(AbstractOutputBuffer.java:305) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:792) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.Response.action(Response.java:177) [tomcat-coyote.jar:8.0.43]
	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:352) [catalina.jar:8.0.43]
	at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:320) [catalina.jar:8.0.43]
	at org.apache.catalina.connector.Response.flushBuffer(Response.java:496) [catalina.jar:8.0.43]
	at org.apache.catalina.connector.ResponseFacade.flushBuffer(ResponseFacade.java:318) [catalina.jar:8.0.43]
	at javax.servlet.ServletResponseWrapper.flushBuffer(ServletResponseWrapper.java:176) [servlet-api.jar:3.1.FR]
	at org.springframework.http.server.ServletServerHttpResponse.flush(ServletServerHttpResponse.java:95) [spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.writeFrameInternal(AbstractHttpSockJsSession.java:355) [spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.writeFrame(AbstractSockJsSession.java:321) [spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.sendHeartbeat(AbstractSockJsSession.java:254) [spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession$HeartbeatTask.run(AbstractSockJsSession.java:450) [spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) [spring-context-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_121]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_121]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_121]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_121]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
21:31:16.794 [SockJsScheduler-1] ERROR o.s.s.s.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task.
org.springframework.web.socket.sockjs.SockJsTransportFailureException: Failed to write SockJsFrame content='h'; nested exception is org.apache.catalina.connector.ClientAbortException: java.io.IOException: APR error: -730054
	at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.writeFrame(AbstractSockJsSession.java:338) ~[spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.sendHeartbeat(AbstractSockJsSession.java:254) ~[spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession$HeartbeatTask.run(AbstractSockJsSession.java:450) ~[spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_121]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_121]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_121]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_121]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
Caused by: org.apache.catalina.connector.ClientAbortException: java.io.IOException: APR error: -730054
	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:356) ~[catalina.jar:8.0.43]
	at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:320) ~[catalina.jar:8.0.43]
	at org.apache.catalina.connector.Response.flushBuffer(Response.java:496) ~[catalina.jar:8.0.43]
	at org.apache.catalina.connector.ResponseFacade.flushBuffer(ResponseFacade.java:318) ~[catalina.jar:8.0.43]
	at javax.servlet.ServletResponseWrapper.flushBuffer(ServletResponseWrapper.java:176) ~[servlet-api.jar:3.1.FR]
	at org.springframework.http.server.ServletServerHttpResponse.flush(ServletServerHttpResponse.java:95) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.writeFrameInternal(AbstractHttpSockJsSession.java:355) ~[spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.writeFrame(AbstractSockJsSession.java:321) ~[spring-websocket-4.2.8.RELEASE.jar:4.2.8.RELEASE]
	... 10 common frames omitted
Caused by: java.io.IOException: APR error: -730054
	at org.apache.coyote.http11.InternalAprOutputBuffer.writeToSocket(InternalAprOutputBuffer.java:292) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.InternalAprOutputBuffer.writeToSocket(InternalAprOutputBuffer.java:245) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:214) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.AbstractOutputBuffer.flush(AbstractOutputBuffer.java:305) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:792) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.coyote.Response.action(Response.java:177) ~[tomcat-coyote.jar:8.0.43]
	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:352) ~[catalina.jar:8.0.43]
	... 17 common frames omitted

需要在修改tomcat配置文件:

<Connector port="33011" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="20000" maxThreads="1000" URIEncoding="UTF-8"  keepAliveTimeout="0"/>

====================================

关于keepAliveTimeout="0":

举例

  1. 某日,你的人品爆发,网站突然来了 1000 个人,那么 tomcat 将消耗 1000 个连接去处理这些请求

  2. 当请求返回后,这 1000 个连接并没有马上销毁,而是全部处于 wait 状态

  3. 这时你的网站又来了 1000 个人(人品持续爆发),但之前那 1000 个连接是无法接受新的请求的(全部处于 wait 状态),所以你现在只有 24 个连接可以使用,so,其他 976 人陷入了漫长的等待中。。。。

  4. 5分钟后,最初的 1000 个连接被逐渐释放了,这时你又有 1000 个连接可以使用了

  5. 无奈那些陷入等待的 976 人已经走的差不多了,就只剩下了 3 个,但是值得高兴的是,因为有了可用连接,他们都可以愉快的连接到你的网站,快乐的玩耍了

故事讲到这里我想你也明白了是什么导致的问题,是因为那些处于 wait 的连接太多,导致可用连接应接不暇。那么,如何优化,答案很简单,禁用 wait ,让连接在返回后立马关闭,成为一个可用连接。

以 tomcat 为例

<Connector port="33011" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="20000" maxThreads="1000" URIEncoding="UTF-8" keepAliveTimeout="0" />

注意 keepAliveTimeout="0" 即为关键所在,其他 server 都会有相关配置,有兴趣的自己去翻翻文档。

 

本文转载自:http://www.cnblogs.com/zhjh256/p/6052102.html

robinjiang
粉丝 13
博文 54
码字总数 8164
作品 0
南京
程序员
私信 提问
日志工具 - boot-websocket-log

boot-websocket-log spring boot系统中使用websocket技术实时输出系统日志到浏览器端 本项目使用如下相关技术: 1.websocket技术:WebSocket(stopmp服务端),stomp协议,sockjs.min.js,s...

KL博客
2018/08/24
0
0
Spring消息之WebSocket

一、WebSocket简介 WebSocket 的定义?WebSocket是HTML5下一种全双工通信协议。在建立连接后,WebSocket服务器端和客户端都能主动的向对方发送和接收数据,就像Socket一样。 WebSocket 的由来...

jmcui
2018/05/06
0
0
在vue中使用SockJS实现webSocket通信

最近接到一个业务需求,需要做一个聊天信息的实时展示的界面,这就需要和服务器端建立webSocket连接,从而实现数据的实时获取和视图的实时刷新.在此将我的实现记录下来,希望可以给有同样需求的人...

慢思考快行动
2018/08/28
0
0
对于不支持websocket的采用何种方式替代?ScokJs

用tomcat作为服务器端,客户端浏览器支持就直接采用websocket,但有些客户端浏览器不支持,采用什么方式替代好呢,用了sockJs,怎么不起作用了? var sock = new SockJS("/msgChannel"); sock...

阿森lin1991
2014/09/19
2.4K
2
Spring+Websocket实现消息的推送

Websocet服务端实现 WebSocketConfig.java @Configuration@EnableWebMvc@EnableWebSocketpublic class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { ......

ldl123292
2014/08/19
0
90

没有更多内容

加载失败,请刷新页面

加载更多

Guava RateLimiter + AOP注解实现单机限流、统计QPS

1、基于springboot项目pom.xml添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency><d......

铁骨铮铮
35分钟前
3
0
龙芯版办公软件下载

金山wps office   rpm包:http://ftp.loongnix.org/os/loongnix/1.0/os/Packages/w/wps-office-10.8.0.6472-1.a20p1.mips64el.rpm   deb包:http://packages.deepin.com/loongson/pool/......

gugudu
40分钟前
2
0
BI报表分析和数据可视化,推荐这三个开源工具!

开源篇 一、Superset 1、技术架构:Python + Flask + React + Redux + SQLAlchemy 2、使用人群: (1)开发/分析人员做好看板,业务人员浏览看板数据 (2)业务人员可自行编辑图表,查看满足...

飓风2000
47分钟前
3
0
CountDownLatch

CountDownLatch的概念 CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。 CountDownLatch能够使一个线程在等待另外一些线程...

少年已不再年少
56分钟前
2
0
centos7 新手阿里云服务器安装mongodb

简介 MongoDB 是一个基于分布式 文件存储的NoSQL数据库 由C++语言编写,运行稳定,性能高 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案 MongoDB特点 模式自由 :可以把不同结构的文档存...

醉雨
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部