我尝试使用Sun JRE的HTTP服务器。在阅读了两次文档后,我仍然感到困惑。
com.sun.net.httpserver.Filter javadoc说明如下
要求此过滤器预先/后处理给定的交换。过滤器可以:
- 检查或修改请求标头
- 通过创建合适的过滤器流并调用HttpExchange.setStreams(InputStream,OutputStream)来过滤请求主体或响应主体
- 在交换中设置属性对象,其他过滤器或交换处理程序可以访问。
决定:
- 通过调用Filter.Chain.doFilter(HttpExchange)来调用链中的下一个过滤器
- 通过不调用Filter.Chain.doFilter(HttpExchange)来终止调用链
如果选项1是上面的,那么当doFilter()返回链中的所有后续过滤器时,都会被调用,并且可以检查或修改响应头。 如果上面的选项2.,那么这个过滤器必须使用HttpExchange发回适当的响应
什么不清楚,什么决定过滤器何时是过程前或过程后过滤器。 正如我所假设的,后处理过滤器在 HttpHandler之后运行,因此它可以与HttpExchange一起使用HttpHandler修改的内容。但是,过滤器只被调用一次,因此必须有一个“魔术”决定过滤器在处理程序之前或之后运行。
请帮我说清楚。
答案 0 :(得分:2)
每个过滤器都是前置和后置过滤器。我的意思是请求在它通过堆栈时通过它,然后响应通过它返回到客户端的路上。调用过滤器的顺序取决于您在web.xml
文件中安装过滤器的顺序。
如果您将其用作预过滤器,则可以修改InputStream
,如果您想将其作为帖子,则可以修改OutputStream
。您甚至可以通过链接传递自己的InputStream
和OutputStream
。
所以,例如,您有一些Filter1
,Filter2
和Filter3
。在处理之前,InputStream
首先会经历Filter1
,然后是Filter2
,最后是Filter3
。生成的OutputStream
会在发送到客户端之前返回Filter3
,然后Filter2
,最后返回Filter1
。因此,通过这种方式,您可以修改预处理和/或后处理。
答案 1 :(得分:1)
我自己对此很纳闷,我看不出setStreams
方法如何对此有所帮助。我可以做到这一点的唯一方法是包装HttpExchange。
此示例显示了如何通过过滤器应用gzip压缩:
https://gist.github.com/Crydust/7e4e9228cd95febccdc58f0501c1e327
答案 2 :(得分:1)
Filter.doFilter() 只被调用一次,在 HttpHandler.handle() 被调用之前。
这意味着您无法在处理程序运行后修改 HTTP 响应的内容。所以,它更自然地是一个预过滤器。
然而,在你的 doFilter() 实现中,你可以用你自己的 FilterOutputStream 包裹响应的 OutputStream,这样你就可以拦截对 HttpExchange.getResponseBody().write(...) 的调用。
class MyFilter extends Filter {
@Override
public void doFilter(HttpExchange exch, Chain chain) throws IOException {
exch.setStreams(null, new MyInterceptedOutputStream(exch.getResponseBody()));
chain.doFilter(exch);
}
...
}
这个 MyInterceptedOutputStream 类需要扩展 OutputStream 并实现其常用方法(write() 和 close() em>)
一个技巧:您的包装器必须确保在调用 HttpExchange.sendResponseHeaders() 之前不会向原始 OutputStream 写入任何内容。这意味着您必须确保您的包装器构造函数(上面示例中的 MyInterceptedOutputStream(OutputStream os))不写入任何内容,例如与 GZIPOutputStream() 不同!
奖励:压缩流的 OutputStream 包装器示例...并在 HttpFilter.doFilter()
中工作import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;
public class GZIPDelayedOutputStream extends OutputStream {
GZIPOutputStream gzipStream;
OutputStream originalStream;
public GZIPDelayedOutputStream(OutputStream os) {
super();
originalStream = os;
}
private void createGzipStreamIfNecessary() throws IOException {
if (gzipStream == null) {
gzipStream = new GZIPOutputStream(originalStream);
}
}
@Override
public void write(int b) throws IOException {
createGzipStreamIfNecessary();
gzipStream.write(b);
}
@Override
public void write(byte buf[]) throws IOException {
createGzipStreamIfNecessary();
gzipStream.write(buf);
}
@Override
public void write(byte[] buf, int off, int len) throws IOException {
createGzipStreamIfNecessary();
gzipStream.write(buf, off, len);
}
@Override
public void close() throws IOException {
createGzipStreamIfNecessary();
gzipStream.close();
}
}