【问题标题】:Sun HTTPServer - how can I write post-process filter?Sun HTTPServer - 我如何编写后处理过滤器?
【发布时间】:2013-01-29 21:07:13
【问题描述】:

我尝试使用 Sun JRE 的 HTTP 服务器做一些事情。看了两遍文档,我还是一头雾水。

com.sun.net.httpserver.Filter javadoc 说明如下

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

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

    • 通过调用 Filter.Chain.doFilter(HttpExchange) 调用链中的下一个过滤器
    • 通过不调用 Filter.Chain.doFilter(HttpExchange) 来终止调用链

    如果采用上述选项 1.,则当 doFilter() 返回时,Chain 中的所有后续过滤器都已被调用,并且可以检查或修改响应标头。 如果采用上述选项 2.,则此过滤器必须使用 HttpExchange 发送回适当的响应

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

请帮我说清楚。

【问题讨论】:

    标签: java com.sun.net.httpserver


    【解决方案1】:

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

    如果您将其用作前置过滤器,您将修改 InputStream,如果您希望将其用作 Post,您将修改 OutputStream。您甚至可以将自己的InputStreamOutputStream 向下传递到链中。

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

    【讨论】:

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

    我自己也对此感到疑惑,但我不明白setStreams 方法对此有何帮助。我能做到这一点的唯一方法是包装 HttpExchange。

    这个例子展示了如何使用过滤器应用 gzip 压缩:

    https://gist.github.com/Crydust/7e4e9228cd95febccdc58f0501c1e327

    【讨论】:

      【解决方案3】:

      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() 不同!

      Bonus: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();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-19
        • 1970-01-01
        • 2013-07-04
        • 2011-08-03
        • 2013-12-15
        • 2011-04-18
        • 1970-01-01
        相关资源
        最近更新 更多