Java Sun HTTPServer-如何编写后处理筛选器?

Java Sun HTTPServer-如何编写后处理筛选器?,java,com.sun.net.httpserver,Java,Com.sun.net.httpserver,我正在尝试使用Sun JRE的HTTP服务器。在阅读了两遍文档之后,我仍然感到困惑 javadoc说: 要求此筛选器对给定的交换进行预处理/后处理。过滤器可以: 检查或修改请求头 通过创建合适的过滤流并调用HttpExchange.setStreams(InputStream,OutputStream),过滤请求正文或响应正文 在exchange中设置其他筛选器或exchange处理程序可以访问的属性对象 决定: 通过调用filter.chain.doFilter(HttpExchange)

我正在尝试使用Sun JRE的HTTP服务器。在阅读了两遍文档之后,我仍然感到困惑

javadoc说:

要求此筛选器对给定的交换进行预处理/后处理。过滤器可以:

  • 检查或修改请求头
  • 通过创建合适的过滤流并调用HttpExchange.setStreams(InputStream,OutputStream),过滤请求正文或响应正文
  • 在exchange中设置其他筛选器或exchange处理程序可以访问的属性对象
  • 决定:

    • 通过调用filter.chain.doFilter(HttpExchange)调用链中的下一个过滤器
    • 通过不调用Filter.chain.doFilter(HttpExchange)终止调用链
    如果选择1。当doFilter()返回时,链中的所有后续过滤器都已被调用,并且可以检查或修改响应头。 如果选择2。在上述情况下,此筛选器必须使用HttpExchange发回适当的响应

我不清楚的是,什么决定了过滤器是预处理过滤器还是后处理过滤器。 正如我所假设的,后处理过滤器是在HttpHandler之后运行的,因此它可以使用HttpExchange处理HttpHandler修改的内容。但是,过滤器只被调用一次,因此必须有一个“魔法”决定过滤器在处理程序之前或之后运行


请帮我弄清楚。

每个过滤器都是前置过滤器和后置过滤器。我的意思是,请求在堆栈中移动时通过它,然后响应通过它返回到客户端。过滤器的调用顺序取决于您在
web.xml
文件中装入过滤器的顺序

如果您将其用作预过滤器,则会修改
InputStream
,如果您希望将其用作帖子,则会修改
OutputStream
。您甚至可以通过链向下传递自己的
InputStream
OutputStream


例如,假设您有一些
Filter1
Filter2
Filter3
InputStream
将首先经过
Filter1
,然后是
Filter2
,最后是
Filter3
,然后再进行处理。生成的
OutputStream
在发送到客户端之前,将通过
Filter3
,然后是
Filter2
,最后是
Filter1
返回。因此,通过这种方式,您可以修改预处理和/或后处理。

我自己也很想知道这一点,我不知道
setStreams
方法如何对此有所帮助。我能做到这一点的唯一方法是包装HttpExchange

此示例演示如何使用筛选器应用gzip压缩:

在调用HttpHandler.handle()之前,只调用一次Filter.doFilter()

这意味着您无法在处理程序运行后修改HTTP响应的内容。所以,它更自然地是一个预过滤器

但是,在doFilter()的实现中,您可以使用自己的FilterOutputStream包装响应的OutputStream,以便拦截对HttpExchange.getResponseBody().write(…)的调用

类MyFilter扩展了过滤器{
@凌驾
public void doFilter(HttpExchange exch,Chain Chain)引发IOException{
exch.setStreams(null,新的MyInterceptedOutputStream(exch.getResponseBody());
链式过滤器(exch);
}
...
}
这个MyInterceptedOutputStream类需要扩展OutputStream并实现其常用方法(write()和close())

有一个技巧:包装器必须确保在调用HttpExchange.sendResponseHeaders()之前不会向原始输出流写入任何内容。这意味着您必须确保您的包装器构造函数(上面示例中的MyInterceptedOutputStream(OutputStream os))不写任何东西,这与例如gziOutputStream()不同

奖励:OutputStream包装器压缩流的示例。。。并在HttpFilter.doFilter()中工作

import java.io.IOException;
导入java.io.OutputStream;
导入java.util.zip.GZIPOutputStream;
公共类GZIPDelayedOutputStream扩展了OutputStream{
gzip输出流gzip流;
OutputStream originalStream;
公共GZIPDelayedOutputStream(OutputStream os){
超级();
原始流=os;
}
private void creategzipstreamifEssential()引发IOException{
如果(gzipStream==null){
gzip流=新的gzip输出流(原始流);
}
}
@凌驾
公共无效写入(int b)引发IOException{
creategzipstreamifEssential();
gzipStream.write(b);
}
@凌驾
公共无效写入(字节buf[])引发IOException{
creategzipstreamifEssential();
gzipStream.write(buf);
}
@凌驾
公共无效写入(字节[]buf,int off,int len)引发IOException{
creategzipstreamifEssential();
写入(buf、off、len);
}
@凌驾
public void close()引发IOException{
creategzipstreamifEssential();
gzipStream.close();
}
}

对不起,
web.xml
是JEE规范的一部分。我知道你提到了Sun HTTP服务器,我相信它是通过代码配置的-但是过滤器堆栈仍然链接在一起,所以你仍然根据你修改的流过滤pre或post。我只是忘记了这个主题。我发现这是以我想象的不同方式实现的。如果我有足够的时间,我会在这里添加一些关于这些东西如何工作的文档