Content-Length不正確導致導出的Excel無法打開

遇到問題

起因是這樣的:我在完成一個Excel導出的功能,寫完代碼之后Excel能夠正常導出下載,但是卻無法打開。

開發(fā)環(huán)境:

JDK 1.8
spring boot 1.5.6.RELEASE
easypoi 3.0.3

調(diào)試過程

  1. 首先我嘗試將生成的Workbook接入本地File,能夠生成Excel文件,并且能夠正常打開,證明Excel生成的代碼沒有問題。
  2. 同樣的生成Excel代碼在另一個項目中能夠正常生成并下載之后也能正常打開,排除是代碼的問題。
  3. 既然生成文件沒有問題,但是經(jīng)過接口傳輸后的Excel卻無法打開,查看Response的Header,同一個Excel多次請求接口Content-Length的值卻不一樣,因此懷疑是這個造成的。
  4. 對比兩個項目的區(qū)別,正常的Response的Header中只有transfer-encoding: chunked,并沒有Content-Length,而不正常的項目中有Content-Length但是沒有transfer-encoding。

分析

Content-Length會影響Response body的接口:HTTP Content-Length深入實踐 。
而Transfer-Encoding表示body的長度不確定:HTTP協(xié)議之Transfer-Encoding 。
因此懷疑是Content-Length的值不正確導致接收的Excel不完整,所以無法打開。而Transfer-Encoding則會完整地接收Excel,因此能夠正常打開。

難點

找到了原因,但是我沒有找到解決的辦法,兩個項目的環(huán)境版本都是一致的。而且也沒有手動的設置Content-Length和Transfer-Encoding,這兩個Header都是spring boot框架自動添加。我也沒有找到更改輸出的控制。最終轉(zhuǎn)化成一個問題:在spring boot中如何控制返回的Response Header中Content-Length還是Transfer-Encoding?

另外基于HTTP的規(guī)則:如果存在Transfer-Encoding(重點是chunked),則在header中不能有Content-Length,有也會被忽視。我嘗試手動添加Transfer-Encoding以覆蓋Content-Length。但是當手動設置Transfer-Encoding之后,接口無法訪問:swagger顯示TypeError: Failed to fetch。服務端日志中也沒有報錯信息。

解決

后來這篇文章:transfer-encoding和content-length的不同實現(xiàn) 給了我思路。Transfer-Encoding 是傳輸數(shù)據(jù)編碼,Content-Encoding 是傳輸內(nèi)容編碼,卻別在于傳輸?shù)膬?nèi)容,于是我想到是否有可能是我改變了body中的內(nèi)容才導致的。
然后我查找了項目,注意到自定了一個LogFilter,用于輸出request和response的header,param,body的內(nèi)容,實際上這里就吧response的body轉(zhuǎn)換成了字符串進行輸入,實際上就是改變了body中的數(shù)據(jù)。

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String basePath = servletRequest.getScheme() + "://" + servletRequest.getServerName()
                + ":" + servletRequest.getServerPort() + request.getRequestURI();
        log.info("request path: " + basePath);
        if (!isSwaggerPath(request)) {
            log.info("headers: {}", getHeaders(request));
            ContentCachingRequestWrapper wrapperRequest = new ContentCachingRequestWrapper(request);
            ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper((HttpServletResponse) servletResponse);
            String urlParams = getRequestParams(request);
            filterChain.doFilter(wrapperRequest, wrapperResponse);

            String requestBodyStr = getRequestBody(wrapperRequest);
            log.info("params[{}] | request body:{}", urlParams, requestBodyStr);

            String responseBodyStr = getResponseBody(wrapperResponse);

            log.info("response body:{}", responseBodyStr);
            wrapperResponse.copyBodyToResponse();
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

嘗試去掉這個Filter,果然response的Header變成了Transfer-Encoding,Excel也能正常打開了。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容