[英]Can't get server sent events and event source to work in JHipster
我正在將JHipster 3.5.0與spring-boot和angular一起使用來構建應用程序。 我想使用服務器發送的事件將更新從后端發送到UI,但是無法正常工作。
這是我的RestController的代碼:
@RestController
@RequestMapping("/api")
public class SSEResource {
private final List<SseEmitter> sseEmitters = new CopyOnWriteArrayList<>();
@RequestMapping(value = "/sse", method = RequestMethod.GET)
@Timed
public SseEmitter getSSE() throws IOException {
SseEmitter sseEmitter = new SseEmitter();
this.sseEmitters.add(sseEmitter);
sseEmitter.send("Connected");
return sseEmitter;
}
@Scheduled(fixedDelay = 3000L)
public void update() {
this.sseEmitters.forEach(emitter -> {
try {
emitter.send(String.valueOf(System.currentTimeMillis()));
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
我的Angaluar控制器如下所示:
(function () {
'use strict';
angular
.module('myApp')
.controller('SSEController', SSEController);
SSEController.$inject = [];
function SSEController() {
var vm = this;
vm.msg = {};
function handleCallback(msg) {
vm.msg = msg.data;
}
vm.source = new EventSource('api/sse');
vm.source.addEventListener('message', handleCallback, false);
}
})
();
當我嘗試使用該代碼時,會收到一個
406不可接受的HTTP狀態
由於請求標頭Accept:“ text / event-stream” 。 如果我手動將標頭更改為接受:“ / *”,然后使用瀏覽器的調試工具重播該請求,則會得到
401未經授權的HTTP狀態
我想我缺少了一些非常簡單的東西,但是我已經檢查了我的SecurityConfiguration和authInterceptor而不了解丟失了什么。
有人可以解釋我在做什么錯嗎?
要回答我自己的問題:解決方案確實非常簡單,也確實不滿意:
我正在將Jhipster與JWT身份驗證結合使用,該身份驗證依賴於HTTP標頭“身份驗證”。 EventSource不支持標題! 看到
解決方案可能是使用支持標題的polyfill。 我通過此事件源polyfill的提交成功地測試了它並支持標題
(function () {
'use strict';
angular
.module('myApp')
.controller('SSEController', SSEController);
SSEController.$inject = ['$scope', 'AuthServerProvider'];
function SSEController($scope, AuthServerProvider) {
var vm = this;
vm.msg = {};
var options = {
headers : {
Authorization : "Bearer " + AuthServerProvider.getToken()
}
}
vm.source = new EventSource('api/sse', options);
vm.source.addEventListener('message', handleCallback, false);
}
})
();
由於某些原因,標頭支持不再包含在master分支或原始polyfill中。 因此,我不確定這是否是正確的方法。 我可能會切換到websockets。
編輯:我想我找到了一種使用標准EventSource的方法。 JWTFilter類包含一種從請求參數中檢索訪問令牌的方法。 所以我可以像這樣使用EventSource:
source = new EventSource('api/sse?access_token=' + AuthServerProvider.getToken());
如此輕松,以至於讓我有些尷尬,以至於我以前從未見過。
在@Jan答案的基礎上,這是我如何修改JWTFilter.resolveToken方法以使其看起來像這樣:
文件 :java / myapp / security / jwt / JWTFilter.java
private String resolveToken(HttpServletRequest request){
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
// pick token as GET parameter
bearerToken = request.getParameter("access_token");
return bearerToken;
}
在前端,這是我使用的相關代碼:
this.eventSource = new EventSource('api/screens/sse?access_token=' + this.authServer.getToken());
this.eventSource.addEventListener('message', evt => {
const messageEvent = evt as MessageEvent;
this._alarmCount = parseInt(messageEvent.data, 10);
});
this.eventSource.onerror = evt => {
console.log('EventSource error' + evt.data);
};
最后,我不得不修改rest控制器以清理完成的發射器:
public SseEmitter getSSE() throws IOException {
SseEmitter sseEmitter = new SseEmitter();
synchronized (this) {
this.sseEmitters.add(sseEmitter);
}
sseEmitter.onCompletion(() -> {
synchronized (this) {
// clean up completed emitters
this.sseEmitters.remove(sseEmitter);
}
});
sseEmitter.send(String.valueOf(System.currentTimeMillis()));
return sseEmitter;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.