代码之家  ›  专栏  ›  技术社区  ›  watery

servlet/rest控制器下载log4j日志文件内容未完全结束

  •  0
  • watery  · 技术社区  · 6 年前

    在一个SpringWeb应用程序中(虽然我不认为这与Spring有关),我创建了一个REST GET资源,允许下载当前的log4j2文件内容,但是请求(来自浏览器和cUrl)不会随着部署在远程生产服务器上的webapp而终止,而它们通常会在我的Windows开发机器上结束。

    而且,cUrl说还有字节要接收:

    * transfer closed with 3 bytes remaining to read
    * stopped the pause stream!
    * Closing connection 0
    curl: (18) transfer closed with 3 bytes remaining to read
    

    这是相关代码:

    // ...
    import org.springframework.http.HttpHeaders;
    // ...
    @RestController
    @RequestMapping(path="/logs", produces="application/json")
    public class LogController {
    
        // ... 
    
        @GetMapping(path="/{appenderName}/contents", produces="text/plain")
        public void download(@PathVariable String appenderName, HttpServletResponse response) {
    
            // ...
    
            org.apache.logging.log4j.Logger rootLogger = LogManager.getRootLogger();
            if(rootLogger instanceof Logger) {
                Logger l = (Logger) rootLogger;
    
                if(l.getAppenders().containsKey(appenderName)) {
                    Appender appender = l.getAppenders().get(appenderName);
    
                    if(appender instanceof FileAppender) {
                        ((FileAppender) appender).getManager().flush();
                        final File f = new File(((FileAppender) appender).getFileName());
    
                        response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain");
                        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + f.getName() + "\"");
    
                        Path tempCopy = Files.createTempFile("log-", null);
                        Files.copy(f.toPath(), tempCopy, StandardCopyOption.REPLACE_EXISTING);
    
                        response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(tempCopy.toFile().length()));
    
                        Reader reader = new FileReader(tempCopy.toFile());
                        IOUtils.copy(reader, response.getWriter());
    
                        reader.close();
                        tempCopy.toFile().delete();
    
                        // ...
    

    Content-length header:在Linux(Ubuntu)服务器上,只有减去 3 文件长度:

    response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(tempCopy.toFile().length() - 3));
    

    当然,如果我不寄,一切都好 Content-Length 标题。

    2 回复  |  直到 6 年前
        1
  •  1
  •   watery    6 年前

    我决定在 Content-Type

    response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain; charset=utf-8");
    

    如果没有它,Linux服务器将返回:

    Content-Type: text/plain;charset=ISO-8859-1
    
        2
  •  0
  •   marme1ad    6 年前

    看起来像 相关问题,因为 Content-Disposition 收割台的 filename

    顺便说一句 应该形成最初是由 RFC 2047 RFC 2231 ; 所以正确的设置方法 文件名 部分是通过编码:

    String fileName = URLEncoder.encode(f.getName(), "UTF-8");
    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
    

    顺便说一句,以后再说 RFC 5987 介绍了在可选的“扩展”参数中使用编码的可能性( filename*

    它使您可以添加可选的“扩展”参数:

    Content-Disposition: attachment;
                         filename="EURO rates";
                         filename*=utf-8''%e2%82%ac%20rates
    

    这里是支持 传真5987 将使用 文件名* 参数和旧的用户代理将忽略它并使用 相反。