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

问题描述 投票:0回答:1

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

<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日志服务器无法在HTTP标头发送错误后设置状态。再次抱歉这是一个重复的问题。希望可以有人帮帮我。

vb.net asp.net-web-api webforms downloading asp.net-apicontroller
1个回答
2
投票

首先,我认为您应该在开始编写实际输出/内容之前添加所有标题。使用缓冲流(这是我即将建议的),这应该没有区别,并且大部分只是语义,但由于标题应该在写入内容之前添加(内容总是最后),它可以避免类似的问题。将来如果您决定使用无缓冲的流。

因此,我建议您相应地重新订购代码:

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()的调用,因为它们过早地清空缓冲区并在您返回状态代码之前将所有内容写入客户端。

新代码:

(...)

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
© www.soinside.com 2019 - 2024. All rights reserved.