猿问

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

在 Spring Web 应用程序中(尽管我认为这与 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);


我认为问题出在Content-length标题上:在 Linux (Ubuntu) 服务器上,只有当我减去3文件长度时才有效:


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

我尝试在下载前将原始文件复制到临时文件,但似乎没有帮助。


当然,如果我不发送任何Content-Length标题,一切都很好。


不负相思意
浏览 139回答 2
2回答

动漫人物

我解决了在Content-Type标题中指定字符集的问题:response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain; charset=utf-8");没有它,Linux 服务器正在返回:Content-Type: text/plain;charset=ISO-8859-1

慕少森

看起来像cURL相关的问题,这是因为Content-Disposition标题的filename部分(这里的问题是关于日志的文件名格式,主要是日期部分)。Content-Disposition应该形成的方式最初由RFC 2047和RFC 2231描述;所以设置filename部分的正确方法是对其进行编码: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这里支持RFC 5987 的用户代理将使用filename*参数,而旧的用户代理将忽略它并filename改为使用。
随时随地看视频慕课网APP

相关分类

Java
我要回答