Angular5 + Spring应用中的服务器推送事件错误:406(不可接受)

6
我正在使用 Angular5 应用程序,需要在仪表板上显示实时数据。我们的后端是用 Spring(v4.x) 编写的,当生成任何服务器事件时,它会发送 API 结果。
但是,当我在 Angular 应用程序中调用此 API 时,它总是给我返回:

GET http://192.168.1.9:8080/proxta/api/student-answered-correctly-by-que_nft 406 (不可接受)

响应头(从网络复制)
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://192.168.1.9:4200
Access-Control-Expose-Headers: Authorization, Link, X-Total-Count
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 0
Content-Type: text/event-stream;charset=UTF-8
Date: Mon, 22 Oct 2018 09:50:59 GMT
Expires: 0
Pragma: no-cache
Vary: Access-Control-Request-Headers
Vary: Access-Control-Request-Method
Vary: Origin
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block

请求头

GET /proxta/api/student-answered-correctly-by-que_nft HTTP/1.1
Host: 192.168.1.9:8080
Connection: keep-alive
Accept: text/event-stream
Cache-Control: no-cache
Origin: http://192.168.1.9:4200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
Referer: http://192.168.1.9:4200/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJleHAiOjE1NDAyMDI3MTIsImlhdCI6MTU0MDIwMDkxMiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiJhMjU2N2FjNS01ZjhjLTQ3OGUtOGI3NS1lMTI1NzFlMTQ0N2QiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.I5UOoVxrrJwa140FRJDSIxuSeySMnHdHJv8rIBPZmGi-jyobKbea7AjZ6dqwblPx3mMXnAqPlp8XxTeDRvRe9BEgHzRxvOmz5Pp3IC1RetLdwjcmM2qKCcUlagkita3GwEpsOCfLWIaCXBufLycmpu1-96gUF-FLqFvYPQnNfK_JZkrGesu33UUKDkEj_PbC8kxK2toLh8PNo7IJ16uhKLdZi7i9oqx2QBCMtYc9uqiPpv-NTbhUZfYnoigG8Tphcr6GtfQJ53eK4NBFStIOpAJ-b6LSixbaCA1W7_x2QHJ-gxp-iscGgXcdouDlXaKMtE-D6IfDzPwQE7MoeAhKsA; session_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJhdGkiOiJhMjU2N2FjNS01ZjhjLTQ3OGUtOGI3NS1lMTI1NzFlMTQ0N2QiLCJleHAiOjE1NDA4MDU3MTIsImlhdCI6MTU0MDIwMDkxMiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiI3NDBjMDAxOC1mNmEwLTQ5NzUtYjg4OS0yMzUxNGI5ZGIwOTEiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.ZE8NLJIie45Ibh6dn1tlpwOmLuf5Lw-ER75cdzNsMDCpy6CPRSIIkBr0gaUJEvLlKQgqOS_LsD5cJ3ugdjYBugN4ye3s3uIccDhn3b0y5Ek1NNPyZSK0b7wWSDIhhdgmCVAmBN5ZKAWr5iNmMzSMpww34ahv8XQ8Q1zJNUUxVrdcXL20PEnEQvSP1fnh8vhzheJGNN7PXPSS2LMOmY515yhIAT8psNluOpOQ38g86IQy-p8CWnUZsNjhfXIxo6Zu9Y9T_witSKuDIeIQ7wAfB_gExPOSIDHaW5XFjSqDfpHIFizBLiXdDDpnAKvNEIHsojMVbP9Z0hRDYFOcQxQ7qg

Angular后端代码

import { Component, OnInit, NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { Http, Headers, RequestOptions, Response, URLSearchParams } from '@angular/http';

@Component({
    selector: 'app-admin-dashboard-content',
    templateUrl: './admin-dashboard-content.component.html',
    styleUrls: ['./admin-dashboard-content.component.css']
})

export class AdminDashboardContentComponent implements OnInit {
    myData: any;
    constructor(private admiDashboardServiceMain: admiDashboardServiceMain,
        private zone: NgZone) {
        this.connect();
    }
    ngOnInit() { }
    connect(): void {
        let headers = new Headers({ 'accept': 'text/event-stream;charset=UTF-8' });
        let options = new RequestOptions({ headers: headers, withCredentials: true });
        let source = new EventSource('http://192.168.1.9:8080/proxta/api/student-answered-correctly-by-que_nft', options)
        source.addEventListener('message', message => {
            console.log(message)
        });
    }
}
  • 我现在只是控制台输出。需要帮助,谢谢。

你确定这不是一个POST端点吗? - Stefan
不是@Stefan,这是一个GET请求 @GetMapping(path = "/api/student-answered-correctly-by-que_nft", produces = "text/event-stream")。 - Bhagvat Lande
2个回答

2

当 Angular(版本 10)发送事件源请求时,使用请求头:Accept: text/event-stream。

如果您的服务器无法生成此类型的输出,则服务器将拒绝该请求。使用 Spring Boot,请求甚至不会到达您的控制器代码。

请查看我的(糟糕的)Spring Boot 代码:

@GetMapping(value = "/flux/{api}", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<Movie> getMovieFlux(
        @PathVariable String api, @RequestParam("title") String title) {
    return service.getMovieFlux(title, api);
}

我只需要更改其中的“produce”部分:
@GetMapping(value = "/flux/{api}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Movie> getMovieFlux(
        @PathVariable String api, @RequestParam("title") String title) {
    return service.getMovieFlux(title, api);
}

或者使用Server-Sent Events:

@GetMapping(value = "/flux/{api}")
public Flux<ServerSentEvent<Movie>> getMovieFlux(
        @PathVariable String api, @RequestParam("title") String title) {
    return service.getMovieFlux(title, api)
            .map(movie -> ServerSentEvent.<Movie>builder().build());
}

1

我不相信EventSource API允许发送HTTP头。尝试像这样创建一个新的事件源对象:

let source = new EventSource('http://192.168.1.9:8080/proxta/api/student-answered-correctly-by-que_nft', {withCredentials: true});

谢谢@cearserg,我尝试了,但是它返回了相同的406响应。 - Bhagvat Lande
你用的是什么浏览器?另外看一下这个帖子,似乎他们遇到了和你一样的问题 https://community.openhab.org/t/sse-over-rest-api/19220/5 - ceaserg
我已经在谷歌浏览器和火狐浏览器上测试过了,但是仍然存在同样的问题。 - Bhagvat Lande
这可能是服务器端的问题。 - ceaserg
2
是的,我正在尝试弄清楚这个问题,因为服务器发送了浏览器无法接受的响应。 - Bhagvat Lande

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接