Контроллер сервлетов / остальных загрузок log4j содержимое файла журнала не заканчивается чисто - PullRequest
0 голосов
/ 26 сентября 2018

В веб-приложении Spring (хотя я не думаю, что это связано с Spring) я создал ресурс REST GET, который позволяет загружать текущее содержимое файла log4j2, но запросы (как из браузеров, так и из cUrl) этого не делаютзавершить работу с веб-приложением, развернутым на удаленном производственном сервере - в то время как они обычно заканчиваются на моей машине для разработки 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: на сервере Linux (Ubuntu) он работает, только если вычесть 3 из длины файла:

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

Я пытался скопировать исходный файл во временный файл перед загрузкой, но, похоже, это не помогло.

Конечно, все нормально, если я не отправляю заголовок Content-Length.

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Я решил указать набор символов в заголовке Content-Type:

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

Без него сервер Linux возвращал:

Content-Type: text/plain;charset=ISO-8859-1
0 голосов
/ 26 сентября 2018

Похоже, проблема связана с cURL , которая возникает из-за части filename заголовка Content-Disposition (вопрос здесь касается формата имени файла журнала, в основном это часть даты).

способ формирования 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.

...