为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

不负相思意 2021-10-13 13:41:03
在 Spring Web 应用程序中(尽管我认为这与 Spring 无关),我创建了一个 REST GET 资源,它允许下载当前的 log4j2 文件内容,但是请求(来自浏览器和 cUrl)不会以webapp 部署在远程生产服务器上——而它们通常在我的 Windows 开发机器上结束。此外,cUrl 说还有字节要接收:* transfer closed with 3 bytes remaining to read* stopped the pause stream!* Closing connection 0curl: (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标题,一切都很好。
查看完整描述

2 回答

?
动漫人物

TA贡献1815条经验 获得超10个赞

我解决了在Content-Type标题中指定字符集的问题:

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

没有它,Linux 服务器正在返回:

Content-Type: text/plain;charset=ISO-8859-1


查看完整回答
反对 回复 2021-10-13
?
慕少森

TA贡献2019条经验 获得超9个赞

看起来像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改为使用。


查看完整回答
反对 回复 2021-10-13
  • 2 回答
  • 0 关注
  • 138 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信