尝试通过 Web api 调用下载文件时,如何解决“发送 HTTP 标头后服务器无法设置状态”错误?

arv*_*ind 0 vb.net webforms download asp.net-web-api asp.net-apicontroller

当我使用 Web api 调用下载文件时,我可以轻松下载该文件。唯一的问题是,在我的错误日志中发送 HTTP 标头后,我收到“服务器无法设置状态”。抱歉,如果这可能是重复的问题,但这里的答案都没有帮助我。

<a href="/api/DownloadDocumentById?documentId=<%=doc.Id %>" download>
                                    <i class="fa fa-download text-primary"></i>
                                </a>
Run Code Online (Sandbox Code Playgroud)
<HttpGet>
    <ActionName("DownloadDocumentById")>
    Public Function DownloadDocumentById(documentId As Integer)
        Dim document = xxxxxxxx

        Dim context = HttpContext.Current

        context.Response.ContentType = document.Type

        context.Response.OutputStream.Write(document.Content, 0, document.Size)

        context.Response.AddHeader("Content-Disposition", Baselib.FormatContentDispositionHeader($"{document.Name}"))

        context.Response.AddHeader("Last-Modified", DateTime.Now.ToLongDateString())

        context.Response.Flush()

        context.Response.End()

        Return HttpStatusCode.OK // Have also tried to create a sub without returning a value
    End Function
Run Code Online (Sandbox Code Playgroud)

如前所述,我可以轻松下载该文档,但 IIS 仍然记录“HTTP 标头已发送后服务器无法设置状态”错误。再次抱歉,这是一个重复的问题。希望可以有人帮帮我。

Vis*_*ent 5

首先也是最重要的,我认为您应该在开始编写实际输出/内容之前添加所有标题。使用缓冲流(这就是我要建议的),这应该不会产生任何影响,并且主要只是语义上的,但由于应在写入内容之前添加标头(内容始终是最后一个),因此可以避免在未来如果您决定使用无缓冲流。

因此,我建议您相应地重新排序代码:

context.Response.ContentType = document.Type

context.Response.AddHeader("Content-Disposition", Baselib.FormatContentDispositionHeader($"{document.Name}"))
context.Response.AddHeader("Last-Modified", DateTime.Now.ToLongDateString())

context.Response.OutputStream.Write(document.Content, 0, document.Size)
Run Code Online (Sandbox Code Playgroud)

现在,如果您使用无缓冲流,则当您调用时,内容将立即发送到客户端OutputStream.Write(),因此为了事后设置 HTTP 结果,您需要确保整个响应都被缓冲,以便在您的内部调用之前不会发送它。请求(操作和控制器)已完成执行。Response.BufferOutput这可以通过在输出任何内容之前设置为来完成True

context.Response.BufferOutput = True

context.Response.ContentType = document.Type

'The rest of the code...
Run Code Online (Sandbox Code Playgroud)

Response.Flush()最后,您需要删除对和 的调用,Response.End()因为它们会过早清空缓冲区,并将所有内容写入客户端,甚至在您返回状态代码之前。

新代码:

(...)

context.Response.BufferOutput = True

context.Response.ContentType = document.Type

context.Response.AddHeader("Content-Disposition", Baselib.FormatContentDispositionHeader($"{document.Name}"))
context.Response.AddHeader("Last-Modified", DateTime.Now.ToLongDateString())

Return HttpStatusCode.OK
Run Code Online (Sandbox Code Playgroud)