Java servlet/rest控制器下载log4j日志文件内容不';完好无损
在Spring web应用程序中(尽管我认为这与Spring无关),我创建了一个REST GET资源,允许下载当前的log4j2文件内容,但请求(来自浏览器和cUrl)不会随着部署在远程生产服务器上的web应用程序而终止,而它们通常会在我的Windows开发机器上结束 此外,cUrl说还有字节要接收:Java servlet/rest控制器下载log4j日志文件内容不';完好无损,java,file,servlets,filereader,spring-restcontroller,Java,File,Servlets,Filereader,Spring Restcontroller,在Spring web应用程序中(尽管我认为这与Spring无关),我创建了一个REST GET资源,允许下载当前的log4j2文件内容,但请求(来自浏览器和cUrl)不会随着部署在远程生产服务器上的web应用程序而终止,而它们通常会在我的Windows开发机器上结束 此外,cUrl说还有字节要接收: * transfer closed with 3 bytes remaining to read * stopped the pause stream! * Closing connection
* 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();
// ...
我认为问题在于内容长度
头:在Linux(Ubuntu)服务器上,只有将3
减去文件长度,它才有效:
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(tempCopy.toFile().length() - 3));
在下载之前,我尝试将原始文件复制到临时文件,但似乎没有任何帮助
当然,如果我不发送任何
内容长度
标题,一切都很好。看起来像cURL相关问题,这是因为内容配置
标题的文件名
部分(这里的问题是关于日志文件名格式的,主要是日期部分)
和最初描述了内容配置
的形成方式;所以设置filename
部件的正确方法是对其进行编码:
String fileName = URLEncoder.encode(f.getName(), "UTF-8");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
补充资料 顺便说一句,后来引入了在可选的“扩展”参数中使用编码的可能性(在我们的例子中,
filename*
);它受到现代浏览器的支持
它使您可以添加可选的“扩展”参数:
Content-Disposition: attachment;
filename="EURO rates";
filename*=utf-8''%e2%82%ac%20rates
这里,支持RFC 5987的用户代理将使用
filename*
参数,而旧的用户代理将忽略该参数,并将使用filename
。我已解决在内容类型
标题中指定字符集的问题:
response.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain; charset=utf-8");
如果没有它,Linux服务器将返回:
Content-Type: text/plain;charset=ISO-8859-1
我在浏览器上也得到了同样的结果,尽管我没有提到(要编辑);我试过你的解决方案,它仍然不起作用,加上现在cUrl说还有
5个字节要读
。错过了它,这也是事实的一部分,在大多数情况下,它是编码相关的东西(标题、正文),让我投票支持你。