«Невозможно отправить без AsyncContext» при обслуживании файлов - PullRequest
0 голосов
/ 10 сентября 2018

Мне нужно написать контроллер MVC «одноразовая загрузка файлов» поверх «контроллера загрузки файлов». После передачи файла клиенту его необходимо удалить с сервера.

Изначально код был написан для обслуживания файлов

import org.springframework.core.io.Resource

@GetMapping("/get/{someParam}")
public ResponseEntity<Resource> downloadFile(Long someParam)
{

    Long fileId = identify(someParam);

    return super.downloadFile(fileId); //This uses a "File repository" service binding file IDs to physical paths

}

protected ResponseEntity<Resource> downloadFile(Long fileId){

    File theFile = resolve(fileId);

    return new FileSystemResource(theFile);

}

Поскольку ResponseEntity является некой «будущей» сущностью, я не могу удалить файл в блоке finally, поскольку он еще не будет обработан.

Итак, сначала я написал асинхронную версию загрузки файла, используя Commons IO для копирования полезной нагрузки. Затем я использовал обратные вызовы, чтобы избавиться от файла только из моего метода.

protected WebAsyncTask<Void> downloadFileAsync(Long fileId,HttpResponse response){ //API method for multiple uses across the application

    InputStream is = new FileInputStream(resolve(fileId));
    Callable<Void> ret = () -> {
        IOUtils.copy(is,response.getOutputStream());
        is.close();
        return null;
    };


    return ret;
}

@GetMapping("/get/{someParam}")
public WebAsyncTask<Void> downloadFile(Long someParam,HttpResponse response)
{
    Long fileId = identify(someParam);
    WebAsyncTask ret = downloadFileAsync(fileId,response);


    ret.onCompletion(()-> fileService.delete(fileId)); //Here I leverage the callback because this file, in this point, is disposable

    return ret;
}

Когда я запускаю вторую версию, я получаю следующую ошибку. Сервер Tomcat 8.0.50

10-Sep-2018 12:20:37.551 AVVERTENZA [ajp-nio-8009-exec-3] org.apache.catalina.core.AsyncContextImpl.setErrorState onError() failed for listener of type [org.apache.catalina.core.AsyncListenerWrapper]
 java.lang.IllegalArgumentException: Cannot dispatch without an AsyncContext
    at org.springframework.util.Assert.notNull(Assert.java:134)
    at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.dispatch(StandardServletAsyncWebRequest.java:128)
    at org.springframework.web.context.request.async.WebAsyncManager.setConcurrentResultAndDispatch(WebAsyncManager.java:369)
    at org.springframework.web.context.request.async.WebAsyncManager.access$200(WebAsyncManager.java:60)
    at org.springframework.web.context.request.async.WebAsyncManager$3.handle(WebAsyncManager.java:311)
    at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.onError(StandardServletAsyncWebRequest.java:144)
    at org.apache.catalina.core.AsyncListenerWrapper.fireOnError(AsyncListenerWrapper.java:49)
    at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:421)
    at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:370)
    at org.apache.coyote.ajp.AbstractAjpProcessor.asyncDispatch(AbstractAjpProcessor.java:745)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:666)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1539)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1495)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

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

Что не так с моим кодом? Я не опубликовал это полностью, чтобы сохранить его простым, но отладка, я вижу, что операция записи завершается успешно с правильной полезной нагрузкой.

1 Ответ

0 голосов
/ 27 июня 2019

У меня была такая же проблема. В моем случае решением было настроить AsyncTaskExecutor:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setDefaultTimeout(-1);
        configurer.setTaskExecutor(asyncTaskExecutor());
    }

    @Bean
    public AsyncTaskExecutor asyncTaskExecutor() {
        // an implementaiton of AsyncTaskExecutor
        return new SimpleAsyncTaskExecutor("async");
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...