You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Web API发送HTTP Headers后触发的状态错误?

解决ASP.NET API返回文件后触发的HTTP Headers已发送错误

问题背景

我有一个通过HttpGet调用的API,逻辑如下:

  • 请求验证通过:直接返回Excel或CSV格式的报告文件
  • 请求验证失败:返回包含错误码和信息的Json Result对象

API调用可成功在浏览器下载文件,但全局应用错误处理器会触发如下错误:

System.Web.HttpException (0x80004005): Server cannot set status after HTTP headers have been sent. at System.Web.HttpResponse.set_StatusCode(Int32 value) at System.Web.Http.WebHost.HttpControllerHandler.<CopyResponseStatusAndHeadersAsync>d__31.MoveNext()

推测是函数在发送HTTP Headers后仍试图返回Nothing,导致Web API框架后续尝试修改响应头引发冲突。


相关代码

API控制器方法

<HttpGet>
Public Function AdvReport(APIKey As String, SubID As String) As Object
    Dim lRes As New Result

    Try
        ' Check Key
        If APIKey Is Nothing OrElse APIKey.Length = 0 Then Return lRes.Init(Result.ResultCode.NoAction, "API Key is missing")
        lRes = APIKeyClass.APIHit(APIKey)
        If lRes.NoSuccess Then Return lRes

        ' Get RepID
        If String.IsNullOrEmpty(SubID) Then Return lRes.Init(Result.ResultCode.NoAction, "SubID is missing")
        SubID = Encrypter.Decrypt(SubID)
        If SubID.Length = 0 OrElse Not IsNumeric(SubID) Then Return lRes.Init(Result.ResultCode.NoAction, "Invalid SubID")

        ' Load Advanced Report Subscription 
        Dim lSub As New AdvRepSubClass
        lRes = lSub.Load(CInt(SubID))
        If lRes.NoSuccess Then Return lRes

        If Not lSub.API Then Return lRes.Init(Result.ResultCode.NoAction, "Report not enabled for API access")

        ' Generate report
        If lRes.IsSuccess Then lRes = lSub.GetReportBin(Nothing, False)

        If lRes.IsSuccess Then LogClass.Log(Nothing, "API AdvReport", "Report Name: " + lSub.Title + "; Result: " + If(lRes.IsSuccess, "Success; Rows Affected: " + lRes.RowsAffected.ToString, lRes.Info) + "; API Key: " + APIKey, LogClass.LogTable.AdvRep, lSub.AdvRepID)

        ' Download it
        Try
            DownloadByteArray(CType(lRes.RetInfo, Byte()), GetReportFileName(lSub.Title, lSub.RepType), False)
            Return Nothing
        Catch ex As Exception
            lRes.Init(Result.ResultCode.Err, ex.Message)
        End Try

        Return lRes

    Catch ex As Exception
        Return lRes.Init(Result.ResultCode.Err, ex.Message)
    End Try
End Function

DownloadByteArray方法

Public Sub DownloadByteArray(aContent As Byte(), aFileName As String, aPreview As Boolean)

    Try
        HttpContext.Current.Response.Buffer = False
        HttpContext.Current.Response.Clear()
        HttpContext.Current.Response.AddHeader("Content-Disposition", If(aPreview, "inline", "attachment") + "; filename=""" & aFileName & """")
        If aPreview Then HttpContext.Current.Response.ContentType = Helper.GetContentType(aFileName) Else HttpContext.Current.Response.ContentType = "application/octet-stream"
        HttpContext.Current.Response.AddHeader("Content-Length", aContent.Length.ToString())
        HttpContext.Current.Response.BinaryWrite(aContent)
        HttpContext.Current.Response.Flush()
        HttpContext.Current.Response.SuppressContent = True
        HttpContext.Current.ApplicationInstance.CompleteRequest()
    Catch ex As Exception
        Dim lUserID As String = If(HttpContext.Current.Session IsNot Nothing AndAlso HttpContext.Current.Session("UserID") IsNot Nothing, HttpContext.Current.Session("UserID").ToString, Nothing)
        LogClass.Log(Nothing, lUserID, "DownloadByteArray", String.Concat("Doc: ", aFileName, "; Ex: ", ex.ToString()))
    End Try
End Sub

解决方案

核心问题是:直接操作HttpContext.Current.Response发送文件后,Web API框架仍会尝试处理控制器方法的返回值(哪怕是Nothing),导致框架试图修改已发送的HTTP头,触发错误。

具体修改

修改API方法中的文件下载逻辑,在成功发送文件后直接终止请求流程,不让Web API框架继续处理返回值:

' Download it
Try
    DownloadByteArray(CType(lRes.RetInfo, Byte()), GetReportFileName(lSub.Title, lSub.RepType), False)
    ' 通知ASP.NET完成当前请求处理,终止后续流程
    HttpContext.Current.ApplicationInstance.CompleteRequest()
    ' 直接退出方法,避免执行后续Return语句
    Exit Function
Catch ex As Exception
    lRes.Init(Result.ResultCode.Err, ex.Message)
End Try

关键说明

  • 不要使用Response.End():它会抛出ThreadAbortException,可能引发额外异常
  • ApplicationInstance.CompleteRequest():让ASP.NET正常完成当前请求的生命周期,不会中断线程,同时阻止Web API框架后续处理响应头
  • Exit Function:确保控制器方法不再返回任何值,彻底终止方法执行

修改后,Web API框架不会再尝试修改已发送的HTTP头,即可消除该错误。


内容的提问来源于stack exchange,提问作者navigator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:20:08