之前写过springboot和websocket整合的例子,https://blog.csdn.net/u014203449/article/details/102902078

在微服务中,页面与后台服务器的交互一般要通过网关,所以网关是否支持长链接也得调试一把。

springcloud中有两个网关组件zuul和gateway。

经查阅zuul是不支持长链接的,而gateway支持长链接。并且zuul底层是同步阻塞基于servlet,而gateway是基于netty、webflux异步非堵塞,性能更好。

现在来看看gateway和websoket的整合。

 

建立一个eureka项目,不赘述了。

建立提供websocket业务的服务wisdomclass-demo,注册到注册中心,websoket的配置也是和上篇文章一样。https://blog.csdn.net/u014203449/article/details/102902078

主要是gateway的配置,上个配置文件。主要看cloud.gateway.routes的配置:

server:
  port: 9006

spring:
  application:
    name: wisdomclass-gateway
  servlet:
    multipart:
      enabled: true #使用http multipart上传处理
      max-file-size: 100MB #单个文件的最大长度为100MB,默认1mb
      max-request-size: 100MB #请求的总数据大小
      file-size-threshold: 1MB #文件大小阈值,当大于这个阈值时将写入到磁盘,否则存在内存中,(默认值0 一般情况下不用特意修改)
      location: /  #超过以上阈值时,写入的临时目录,当请求响应完成后,临时文件自动删除
  cloud:
    gateway:
      routes:
        - id: demo
          order: 5
          uri: lb://wisdomclass-demo   #lb代表从注册中心获取服务,将path的请求路由到uri
          predicates:
            - Path=/wisdomclass-demo/**
          filters:
            - StripPrefix=1    #除去第一个/前缀,比如请求/wisdomclass-demo/demo,会去除前缀/wisdomclass-demo,请求到路由服务的 /demo接口
            - name: Hystrix    #熔断
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback  #网关的统一熔断接口
        - id: demo
          uri: lb:ws://wisdomclass-demo     #wesocket协议
          order: 2
          predicates:
            - Path=/wisdomclass-demo/topic/**
          filters:
            - StripPrefix=1
        - id: demo
          uri: lb:ws://wisdomclass-demo
          order: 3
          predicates:
            - Path=/wisdomclass-demo/app/**
          filters:
            - StripPrefix=1

hystrix:
  command:
    fallbackcmd:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000  #超时时间后进入熔断

#eureka客户端配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9000/eureka/
logging:
  level:
    root: info


主要看cloud.gateway.routes的配置:

id只是个路由标志,我认为没有什么用,两个路由配置id可以相同。

order是执行顺序,两个id相同的路由配置会执行order数值小的。

predicates:是判断请求地址是否符合 value,如果符合会路由到uri 的value地址。

uri:请求符合predicates的,会路由到uri地址。

这个地方其实可以直接写路由的地址,比如baidu.com,会直接将请求转发到baidu。但微服务实例通常有很多,这里不能直接写服务ip端口,如果想按注册中心的服务名来路由,前面要加 lb://, lb://wisdomclass-demo这个配置是路由到服务名为wisdomclass-demo的服务,并且用http协议的方式。

但是wisdomclass-demo这个项目里有关于websocket的内容,用的是websocket协议,不是http,所以在routes配置中,写了多个路由配置,我写的配置是 以app 和topic开头的url,用ws协议路由到wisdomclass-demo服务去通信。其余的请求还是http。因为第二个第三个路由配置的order更小,所以优先执行这两个路由规则,最后执行第一个路由规则。

为什么是app和topic?因为我在stomp设置的频道是他们:

weosocket配置:

package cn.sosuncloud.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;

import javax.servlet.http.HttpSession;
import java.util.Map;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic","/q");
        config.setApplicationDestinationPrefixes("/app");
        config.setUserDestinationPrefix("/user");
    }

//    @Override
//    public void registerStompEndpoints(StompEndpointRegistry registry) {
//        registry.addEndpoint("/gs-guide-websocket").withSockJS();
//    }


    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {

        registry
                .addEndpoint("/gs-guide-websocket")
                .setHandshakeHandler(new DefaultHandshakeHandler() {

                    public boolean beforeHandshake(
                            ServerHttpRequest request,
                            ServerHttpResponse response,
                            WebSocketHandler wsHandler,
                            Map attributes) throws Exception {

                        if (request instanceof ServletServerHttpRequest) {
                            ServletServerHttpRequest servletRequest
                                    = (ServletServerHttpRequest) request;
                            HttpSession session = servletRequest
                                    .getServletRequest().getSession();
                            attributes.put("sessionId", session.getId());
                            HttpHeaders headers = servletRequest.getHeaders();

                        }
                        return true;
                    }}).withSockJS();
    }


    /**
     * 配置客户端入站通道拦截器
     */
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.setInterceptors(createUserInterceptor());
    }

    /**
     *
     * @Title: createUserInterceptor
     * @Description: 将客户端渠道拦截器加入spring ioc容器
     * @return
     */
    @Bean
    public UserInterceptor createUserInterceptor() {
        return new UserInterceptor();
    }

}

频道接受消息和推送:

@Controller
public class GreetingController {

    @Autowired
    SimpMessagingTemplate SMT;

    @MessageMapping(value = "/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) throws Exception {
        Thread.sleep(1000); // simulated delay
        return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
    }
}

可以看到,只有服务端向客户端推送消息的协议是ws,也就是app 和topick的url。

其余建立连接的url  如 /gs-guide-websocket ,和客户端发送消息的url  /hello 还是http。

这里stomp建立连接用的是http。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐