Grails несколько запросов при использовании кодирования передачи chunked - PullRequest
1 голос
/ 14 января 2010

Я загружаю файл через Grails и записываю тот факт, что этот файл был загружен этим пользователем, с кодом вроде:

class MyController {

    private void recordTrackDownload() {
        def d = new Download(session.user, "/path/to/file")
        d.save()
    }

    def download = {
        def f = new File("/path/to/file")
        recordTrackDownload()
        response.contentType = "mime/type"
        response.outputStream << f.newInputStream()
        response.outputStream.flush()
    }
}

И я вижу несколько записей о загрузке для каждого клика. Я подозреваю, что это как-то связано с несколькими запросами, записанными Firefox, и заголовком «Transfer-Encoding: chunked», который я вижу в заголовках Live HTTP. (Это поведение также очевидно в Chromium)

Я также вижу зарегистрированную в терминале ошибку, которая, вероятно, связана с ошибкой в ​​Grails или просто зарегистрированной и игнорируемой ошибкой, но, похоже, она не останавливает фактическую загрузку файла: *

2010-01-14 18:46:16,623 [http-8080-4] ERROR errors.GrailsExceptionResolver  - Executing action [download] of controller [com.tunited.music.DownloadTrackController]  caused exception: ClientAbortException:  java.net.SocketException: Connection reset
org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException: Executing action [download] of controller [com.tunited.music.DownloadTrackController]  caused exception: ClientAbortException:  j
ava.net.SocketException: Connection reset
        at java.lang.Thread.run(Thread.java:636)
Caused by: org.codehaus.groovy.runtime.InvokerInvocationException: ClientAbortException:  java.net.SocketException: Connection reset
        ... 1 more
Caused by: ClientAbortException:  java.net.SocketException: Connection reset
        at com.tunited.music.DownloadTrackController$_closure2.doCall(DownloadTrackController.groovy:35)
        at com.tunited.music.DownloadTrackController$_closure2.doCall(DownloadTrackController.groovy)
        ... 1 more
Caused by: java.net.SocketException: Connection reset
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
        ... 3 more
2010-01-14 18:46:17,091 [http-8080-4] ERROR view.GroovyPageView  - Error processing GroovyPageView: getOutputStream() has already been called for this response
java.lang.IllegalStateException: getOutputStream() has already been called for this response
        at home_ed_dev_nomad_tunited_grails_app_views_error_gsp.run(home_ed_dev_nomad_tunited_grails_app_views_error_gsp:19)
        at java.lang.Thread.run(Thread.java:636)
2010-01-14 18:46:17,092 [http-8080-4] ERROR errors.GrailsExceptionResolver  - getOutputStream() has already been called for this response
java.lang.IllegalStateException: getOutputStream() has already been called for this response
        at java.lang.Thread.run(Thread.java:636)
2010-01-14 18:46:17,100 [http-8080-4] ERROR view.GroovyPageView  - Error processing GroovyPageView: getOutputStream() has already been called for this response
java.lang.IllegalStateException: getOutputStream() has already been called for this response
        at home_ed_dev_nomad_tunited_grails_app_views_error_gsp.run(home_ed_dev_nomad_tunited_grails_app_views_error_gsp:19)
        at java.lang.Thread.run(Thread.java:636)
2010-01-14 18:46:17,103 [http-8080-4] ERROR [/].[grails]  - Servlet.service() for servlet grails threw exception
java.lang.IllegalStateException: getOutputStream() has already been called for this response
        at org.apache.catalina.connector.Response.getWriter(Response.java:610)
        at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:198)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$5.activateDestination(GrailsPageResponseWrapper.java:141)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsRoutablePrintWriter.getDestination(GrailsRoutablePrintWriter.java:41)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsRoutablePrintWriter.flush(GrailsRoutablePrintWriter.java:159)
        at org.codehaus.groovy.grails.web.util.GrailsPrintWriter.flush(GrailsPrintWriter.java:98)
...
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
        at java.lang.Thread.run(Thread.java:636)
2010-01-14 18:46:17,106 [http-8080-4] ERROR [/].[default]  - Servlet.service() for servlet default threw exception
java.lang.IllegalStateException: getOutputStream() has already been called for this response
        at org.apache.catalina.connector.Response.getWriter(Response.java:610)
        at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:198)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$5.activateDestination(GrailsPageResponseWrapper.java:141)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsRoutablePrintWriter.getDestination(GrailsRoutablePrintWriter.java:41)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsRoutablePrintWriter.flush(GrailsRoutablePrintWriter.java:159)
        at org.codehaus.groovy.grails.web.util.GrailsPrintWriter.flush(GrailsPrintWriter.java:98)
...
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
        at java.lang.Thread.run(Thread.java:636)

В идеале я хотел бы, чтобы код моего контроллера выполнялся только один раз, и файл chunked загружался. Я мог бы сделать это, выполнив несколько действий, первое из которых записывает загрузку, а затем перенаправляет на второе, которое загружает файл. Но создание другого перенаправления на пути и необходимость защиты второго URL-адреса с использованием чего-то вроде области видимости флэш-памяти кажется плохим решением. Похоже, что я не знаю, как работает протокол HTTP или Grails, и есть простой способ это исправить.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 18 июля 2012

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

0 голосов
/ 15 января 2010

Действительно простое решение - не разбивать код на части. Если вы установите длину контента, то не должно быть фрагментирования.

Что-то вроде:

response.contentType = "mime/type"
response.contentLength = f.length()
...