gpt4 book ai didi

java - 无法将 Content-Type header 添加到 SSE 端点

转载 作者:行者123 更新时间:2023-12-02 02:51:24 25 4
gpt4 key购买 nike

我有一个 Java 服务器和一个 JavaScript 客户端,它们已成功使用服务器发送事件发送更新。最近,我们被迫在使用 kubernetes 内置的 NGINX 作为服务器和客户端之间的代理之间进行切换,转而使用基于 kong 的代理(通过不同的配置扩展 NGINX)。新的代理缓冲 SSE 通过它打破协议(protocol),并且因为其他应用程序正在使用新的代理,所以我不允许关闭所有缓冲,这就是以前的代理解决问题的方式。作为替代方案,我一直在尝试向 SSE 响应添加 3 个 http header ,以触发 NGINX 关闭此特定端点的缓冲:

"Content-Type" : "text/event-stream"
"Cache-Control", "no-cache"
"X-Accel-Buffering", "no"

我已经能够相对轻松地添加“Cache-Control”和“X-Accel-Buffering” header ,但我尝试了几种不同的方法来添加“Content-Type” header ,但没有任何效果。

下面是第一次尝试,请注意“Content-Type” header 的设置与 RestServiceImpl 中的其他两个 header 相同,但从我的日志来看,添加了其他两个 header ,而“Content-Type”则没有。

@Api
@Path("/service")
public interface RestService {

@GET
@Path("/sseconnect")
@Produces(SseFeature.SERVER_SENT_EVENTS)
EventOutput listenToBroadcast(@Context HttpServletResponse response);

}

@Component
public class RestServiceImpl implements RestService {

@Autowired
private Broadcaster broadcaster;

public RestServiceImpl() {
}

@Override
public EventOutput listenToBroadcast(HttpServletResponse response) {
response.addHeader("Content-Type", "text/event-stream");
response.addHeader("Cache-Control", "no-cache");
response.addHeader("X-Accel-Buffering", "no");
return broadcaster.add();
}
}

public class Broadcaster extends SseBroadcaster {

private final OutboundEvent.Builder eventBuilder =
new OutboundEvent.Builder();

public EventOutput add() {
final EventOutput eventOutput = new EventOutput();
super.add(eventOutput);
return eventOutput;
}

public void sendEvents(Events events, String name) {
final OutboundEvent outboundEvent = eventBuilder.name(name)
.mediaType(MediaType.APPLICATION_JSON_TYPE)
.data(Events.class, events).build();
super.broadcast(outboundEvent);
}
}

在第二次尝试中,我尝试修改“Content-Type” header 的添加方式,如下所示:

@Override
public EventOutput listenToBroadcast(HttpServletResponse response) {
response.setContentType("text/event-stream");
response.addHeader("Cache-Control", "no-cache");
response.addHeader("X-Accell-Buffering", no);
return broadcaster.add();
}

这具有相同的效果,添加了“Cache-Control”和“X-Accell-Bufferig”,但没有添加“Content-Type”。

第三次尝试时,我将 HttpServletResponse 替换为 ContainerResponse

@Override
public EventOutput listenToBroadcast(ContainerResponse containerResponse)
{
final MultivaluedMap<String, Object> headers =
containerResponse.getHeaders();
headers.add("Content-Type", "text/event-stream");
headers.add("Cache-Control", "no-cache");
headers.add("X-Accel-Buffering", "no");
return broadcaster.add();
}

这个解决方案破坏了端点并最终给我一个 406 错误,所以我不能明确地说它不会起作用。可能是一个糟糕的实现,但我没有看到任何东西。

在第四次尝试中,我尝试使用 ContainerResponseFilter 添加 header 。

@Provider
@PreMatching
public class SseResponseFilter implements ContainerResponseFilter {

@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext)
throws IOException {

final MultivaluedMap<String, Object> headers =
responseContext.getHeaders();
final List<Object> contentTypeValues = new ArrayList<Object>();
contentTypeValues.add("text/event-stream");
headers.put("Content-Type", contentTypeValues);

final List<Object> cacheControlValues = new ArrayList<Object>();
cacheControlValues.add("no-cache");
headers.put("Cache-Control", cacheControlValues);

final List<Object> xAccelBufferingValues =
new ArrayList<Object>();
xAccelBufferingValues.add("no");
headers.put("X-Accel-Buffering", xAccelBufferingValues);
}
}

此尝试将“Cache-Control”和“X-Accel-Buffering” header 添加到应用程序中的每个端点,但没有在任何地方添加“Content-Type”。请注意,其中一些其他 api 返回允许设置“Content-Type”的 Response 对象,并且这些 REST 端点正在为每个特定端点正确设置“Content-Type” header 。 SSE 库返回 EventOutput,遗憾的是它不允许我像 Response 那样设置 Content-Type header 。

在第五次尝试中,我用 WriterInterceptor 替换了 ContainerResponseFilter

@Provider
public class SseWriterInterceptor implements WriterInterceptor {

@Override
public void arroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {

final MultivaluedMap<String, Object> headers =
context.getHeaders();
final List<Object> contentTypeValues = new ArrayList<Object>();
contentTypeValues.add("text/event-stream");
headers.put("Content-Type", contentTypeValues);

final List<Object> cacheControlValues = new ArrayList<Object>();
cacheControlValues.add("no-cache");
headers.put("Cache-Control", cacheControlValues);

final List<Object> xAccelBufferingValues =
new ArrayList<Object>();
xAccelBufferingValues.add("no");
headers.put("X-Accel-Buffering", xAccelBufferingValues);
}
}

此解决方案的工作原理与之前的解决方案类似,它向应用程序中的所有端点添加了“Cache-Control”和“X-Accel-Buffering”,但再次省略了“Content-Type”。

总而言之,我似乎无法弄清楚是什么阻止我成功地将“Content-Type” header 添加到我的 SSE 端点。

这个问题类似于: Why does Jersey swallow my "Content-Encoding" header但是,将“Content-Type”添加到 Response 对象的给定解决方案不起作用,因为我使用的是 SSE,它返回一个 EventOutput 对象,而该对象无法添加“Content-Type” header 。

最佳答案

事实证明,Jersey 并不是未设置“Content-Type” header 的罪魁祸首。该应用程序是作为持续部署环境的一部分构建的,该环境附加了许多过滤器,用于日志记录和安全扫描等。这些过滤器之一是在使用 SSE 库时阻止填充“Content-Type” header 。

在本地计算机上运行应用程序与在基于 kubernetes 的开发环境中运行应用程序并看到“Content-Type” header 使用本地中的第一个解决方案正确填充后,我能够确定这是原因。

关于java - 无法将 Content-Type header 添加到 SSE 端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57105777/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com