[英]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.