已經有好長一段時間沒有寫文章。主要仍是我的比較隨性,也在學習別的東西,就顧不上了。今天主要講一下如何經過使用SpringCloud Gateway + WebSocker整合和本身在實踐當中遇到的問題講解一下,但願與你們一塊兒來學習。javascript
想要了解gateway,能夠取SpringCloud官方網站下載個列子。網關的主要做用我在這裏就再也不講解了,就問度娘吧。css
pom.xml maven
依賴網關的配置:html
server:
port: ${USER_PORT:8555}
http2:
enabled: true
compression:
enabled: true
error:
whitelabel:
enabled: false
spring:
cloud:
gateway:
routes:
# =====================================
# to run server
# $ wscat --listen 9000
# to run client
# $ wscat --connect ws://localhost:8080/echo
# - id: websocket_test
# uri: ws://localhost:9000
# order: 9000
# predicates:
# - Path=/echo
# =====================================
- id: grabservice-websocket
uri: lb:ws://bilibili-grabservice
order: 9000
predicates:
- Path=/api/grabservice/mq/**
filters:
- StripPrefix=2
複製代碼
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketAutoConfig implements WebSocketMessageBrokerConfigurer{
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/mq")
.setAllowedOrigins("*")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/matches");
registry.setPreservePublishOrder(true);
}
}
複製代碼
matches
Broker的端口業務@Slf4j
@RestController
public class LiveMatchesController {
@Autowired
private SimpMessagingTemplate messagingTemplate;//這個是重點
@Scheduled(cron = "0/15 * * * * ?")
@SendTo("/matches")
public void matches() {
messagingTemplate.convertAndSend("/matches", "hell world");//這個也是重點(點對點)
}
}
複製代碼
這樣一個簡單的後端推送服務完成。java
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Spring Boot WebSocket+廣播式</title>
</head>
<body onload="disconnect()">
<noscript>
<h2 style="color:#ff0000">貌似你的瀏覽器不支持websocket</h2>
</noscript>
<div>
<div>
<button id="connect" onclick="connect()">鏈接</button>
<button id="disconnect" onclick="disconnect();">斷開鏈接</button>
</div>
<div id="conversationDiv">
<label>輸入你的名字</label> <input type="text" id="name" />
<br>
<label>輸入消息</label> <input type="text" id="messgae" />
<button id="send" onclick="send();">發送</button>
<p id="response"></p>
</div>
</div>
<script src="https://cdn.bootcss.com/sockjs-client/1.3.0/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript"> var stompClient = null; var host="http://192.168.0.249:8555/api/grabservice"; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden'; $('#response').html(); } function connect() { var socket = new SockJS(host+'/mq'); stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { setConnected(true); console.log('Connected:' + frame); stompClient.subscribe('/matches', function(response) { showResponse(response.body); }); }); } function disconnect() { if (stompClient != null) { stompClient.disconnect(); } setConnected(false); console.log("Disconnected"); } function send() { var name = $('#name').val(); var message = $('#messgae').val(); stompClient.send("/chat", {}, JSON.stringify({username:name,message:message})); } function showResponse(message) { var response = $('#response'); response.html(message); } </script>
</body>
</html>
複製代碼
http://192.168.0.249:8555/api/grabservice,是個人網關請求地址,api/grabservice
這是個人請求路由,真正請求的地址看網關的配置,個人後端推送服務端口是8553。 這裏會存在兩個問題jquery
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
log.debug(" origin : {}", request.getHeaders().get(HttpHeaders.ORIGIN).get(0));
headers.setAccessControlAllowOrigin((request.getHeaders().get(HttpHeaders.ORIGIN)).get(0));
headers.setAccessControlAllowCredentials(true);
headers.setAccessControlMaxAge(Integer.MAX_VALUE);
headers.setAccessControlAllowHeaders(Arrays.asList("*"));
headers.setAccessControlAllowMethods(Arrays.asList(HttpMethod.OPTIONS,
HttpMethod.GET, HttpMethod.HEAD, HttpMethod.POST,
HttpMethod.DELETE, HttpMethod.PUT));
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
複製代碼
http://ws://bilibili-grabservice/mq/info
相似的請求中的ws(若是是https://wss),修改成http(wss就修改成https),但必須在WebsocketRoutingFilter以前org.springframework.cloud.gateway.filter.WebsocketRoutingFilter:@Component
public class WebsocketHandler implements GlobalFilter, Ordered {
private final static String DEFAULT_FILTER_PATH = "/mq/info";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String upgrade = exchange.getRequest().getHeaders().getUpgrade();
log.debug("Upgrade : {}", upgrade);
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
log.debug("path: {}", requestUrl.getPath());
String scheme = requestUrl.getScheme();
if (!"ws".equals(scheme) && !"wss".equals(scheme)) {
return chain.filter(exchange);
} else if (DEFAULT_FILTER_PATH.equals(requestUrl.getPath())) {
String wsScheme = convertWsToHttp(scheme);
URI wsRequestUrl = UriComponentsBuilder.fromUri(requestUrl).scheme(wsScheme).build().toUri();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, wsRequestUrl);
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 2;
}
static String convertWsToHttp(String scheme) {
scheme = scheme.toLowerCase();
return "ws".equals(scheme) ? "http" : "wss".equals(scheme) ? "https" : scheme;
}
複製代碼
好了一個基本的wobsocket工程就完成了。web
Spring Cloud Gateway轉發Spring WebSocketspring