尝试通过网络 api 调用下载文件时如何解决 'Server cannot set status after HTTP headers have been sent' 错误?

How to resolve 'Server cannot set status after HTTP headers have been sent' error when trying to download files via web api call?

当我使用网络 api 调用下载文件时,我可以轻松下载文件。唯一的问题是我的错误日志中出现 Server cannot set status after HTTP headers have sent。 抱歉,如果这可能是一个重复的问题,但这里 none 的答案对我有帮助。

<a href="/api/DownloadDocumentById?documentId=<%=doc.Id %>" download>
                                    <i class="fa fa-download text-primary"></i>
                                </a>
<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

如前所述,我可以轻松下载文档,但 IIS 仍然记录 Server cannot set status after HTTP headers have been sent 错误。 再次抱歉,这是一个重复的问题。希望有人能帮助我。

首先,我认为您应该在开始编写实际的 output/content 之前添加所有 headers。对于缓冲流(这是我要建议的),这应该没有什么区别,而且主要只是语义上的,但是由于 headers 应该添加 before 写content(内容总是最后)如果你决定使用无缓冲流,它可能会避免将来出现类似问题。

因此,我建议您 re-order 您的代码相应:

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)

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

context.Response.BufferOutput = True

context.Response.ContentType = document.Type

'The rest of the code...

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

新代码:

(...)

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