Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Tomcat 8禁用分块编码过滤器_Java_Tomcat_Servlet Filters_Chunked Encoding_Embedded Tomcat 8 - Fatal编程技术网

Java Tomcat 8禁用分块编码过滤器

Java Tomcat 8禁用分块编码过滤器,java,tomcat,servlet-filters,chunked-encoding,embedded-tomcat-8,Java,Tomcat,Servlet Filters,Chunked Encoding,Embedded Tomcat 8,我们有一个VPN,有时用来远程连接到站点,结果却发现tomcat似乎使用的分块编码常常会导致大量JavaScript文件被截断。为了解决这个问题,我想为JS文件构建一个Tomcat过滤器,一次性发送它们 通过阅读这些文章,我试着自己尝试一下,并尝试如下实现它 我用一个自定义的过滤器映射将过滤器连接到我的上下文中 new CustomFilterMap( new String[]{"*.js"}, new String[]{"REQUEST"} ) 这部分实际上工作得很好,我的过

我们有一个VPN,有时用来远程连接到站点,结果却发现tomcat似乎使用的分块编码常常会导致大量JavaScript文件被截断。为了解决这个问题,我想为JS文件构建一个Tomcat过滤器,一次性发送它们

通过阅读这些文章,我试着自己尝试一下,并尝试如下实现它

我用一个自定义的过滤器映射将过滤器连接到我的上下文中

new CustomFilterMap(
    new String[]{"*.js"},
    new String[]{"REQUEST"}
)
这部分实际上工作得很好,我的过滤器似乎适用于JS文件。现在,我没有得到这么好的工作部分是实际的过滤器

public class NoChunkEncodedJSFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        val unversionedServletPath = request.getRequestURI().substring(request.getRequestURI().indexOf("/js"));
        val requestFilePath = getServletContext().getRealPath(unversionedServletPath);

        if (requestFilePath != null) {
            File requestedFile = new File(requestFilePath);
            if (requestedFile.exists()) {
                val fileSize = Math.toIntExact(requestedFile.length());

                val out = response.getWriter();
                val wrappedResponse = new NonEncodedResponse(response, fileSize);
                filterChain.doFilter(request, wrappedResponse);

                out.write(wrappedResponse.toString(), "UTF-8");
                out.close();
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}
我的非公开回答是:

public class NonEncodedResponse extends HttpServletResponseWrapper {
    private ByteArrayOutputStream baos;

    public String toString() {
        try {
            return baos.toString("UTF-8");
        } catch (UnsupportedEncodingException unsuportedEncodingException) {
            return baos.toString();
        }
    }

    /**
     * Constructs a response adaptor wrapping the given response.
     *
     * @param response The response to be wrapped
     * @throws IllegalArgumentException if the response is null
     */
    public NonEncodedResponse(HttpServletResponse response, Integer fileSize) {
        super(response);

        this.setContentLength(fileSize);
        this.setBufferSize(fileSize);
        super.setContentLength(fileSize);
        super.setBufferSize(fileSize);

        baos = new ByteArrayOutputStream(fileSize);
    }

    @Override
    public PrintWriter getWriter(){
        return new PrintWriter(baos);
    }
}
现在,最初我尝试根本不包装响应,只调用
response.setBufferSize(fileSize)
response.setContentLength(文件大小)
但这似乎对我的输出没有实际影响,当我查看标题时,我仍然使用没有固定内容长度的分块传输编码。(我也尝试过这样设置自定义标题,但也没有看到它附加到我的响应中。我假设以其基本形式进入过滤器的响应是某种形式的只读。)

我还尝试使用包装器,通过直接从文件读取和发送字节来绕过其输出流

val fileContents = Files.readAllBytes(Paths.get(requestFilePath));
out.write(new String(fileContents));
因为看起来,即使我试图修复内容长度的尝试失败了,但在尝试调试时,我仍然只能在浏览器的“网络”选项卡中看到部分文件作为整体发送

总而言之,现在我有了这样的服务文件(可能不太理想),更不理想的是,它仍然说
Transfer Encoding:chunked
,尽管我尽了全力在包装器和原始响应上设置了固定的内容长度。我现在可以在我的内容上添加一个自定义标题,这样我就知道它正在通过我的过滤器运行。似乎出于某种原因,它仍然是块编码的


有人能告诉我我做错了什么,或者过滤器是否可以用来禁用分块编码(我相信我从谷歌搜索中看到了一些提示,但事实是我不知道)。我很乐意接受关于这个问题的任何和所有建议,我不再有想法尝试,我当然不知道我在做什么。

因此,我实际上通过恢复到我原来的方法,完全抛弃我的包装器,并将
filterChain.doFilter
移动到我的代码块的末尾来实现这一点。我真的不知道为什么与我之前所做的相比,这是有效的,因为我不得不承认我根本不知道
filterChain.doFilter
实际上做了什么。这是我最终的结果,让事情运转起来

public class NoChunkEncodedJSFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        val requestFilePath = this.getRealFilePath(request.getRequestURI());
        File requestedFile = new File(requestFilePath);

        if (requestedFile.exists()) {
            val fileSize = Math.toIntExact(requestedFile.length());
            val fileContents = Files.readAllBytes(Paths.get(requestFilePath));

            response.reset();
            response.setHeader("Content-Length", String.valueOf(fileSize));
            response.setContentLength(fileSize);

            ServletOutputStream sos = response.getOutputStream();
            sos.write(fileContents);
            sos.close();
        }

        filterChain.doFilter(request, response);
    }

    private String getRealFilePath(String requestURI) {
        val unversionedServletPath = requestURI.substring(requestURI.indexOf("/js"));
        return getServletContext().getRealPath(unversionedServletPath);
    }
}
现在我唯一剩下的问题是,有没有更聪明的方法来获取文件的缓冲区数据,还是每次都要从磁盘重新读取文件?我假设我的文件可能已经被加载到内存中,准备提供服务。在这里,我第二次将它加载到内存中,我想这不是很有效