使用 ASP.NET Web API 2,如果我想返回带有 Unauthorized 状态代码的 HttpResponseMessage,我将获得不同的响应 header - 有或没有 WWW-Authenticate header 字段 - 取决于此响应消息是否有内容。
根据 Status Code Definitions,WWW-Authenticate header 字段是未授权响应的必填字段.
响应中缺少 WWW-Authenticate 头字段会导致下一个请求出错。
要查看问题,您可以创建一个新的 Web API 项目并添加一个简单的测试 Controller :
public class TestController : ApiController
{
public HttpResponseMessage Get()
{
var responseMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
// Content = new StringContent("You are not authorized"),
};
return responseMessage;
}
}
如果响应消息没有内容,我们的调用将得到正常的 401 响应:
有回复:
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Bearer
X-SourceFiles: =?UTF-8?B?RDpcUHJvamVjdHNcVGVzdEFwaVxUZXN0QXBpXGFwaVxUZXN0?=
X-Powered-By: ASP.NET
Date: Fri, 01 May 2015 05:31:20 GMT
Content-Length: 0
如果我们向响应消息添加内容(取消注释内容行),则每秒响应将不是 401,而是 500
带有 401 的响应将具有以下 header :
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 22
Content-Type: text/plain; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcUHJvamVjdHNcVGVzdEFwaVxUZXN0QXBpXGFwaVxUZXN0?=
X-Powered-By: ASP.NET
Date: Fri, 01 May 2015 05:34:38 GMT
You are not authorized
500 的回复会说
Server cannot append header after HTTP headers have been sent.
Description: an unhandled exception occurred during the execution of the current web request.Please review the stack trace for more information about the error and where it originated in the code..... Exception Details: System.Web.HttpException: Server cannot append header after HTTP headers have been sent.
所以它看起来像是因为以前的响应是非法的——它们不包含 WWW-Authenticate header 属性。
但即使我尝试手动添加 WWW-Authenticate 也无济于事
public class TestController : ApiController
{
public HttpResponseMessage Get()
{
var responseMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("You are not authorized"),
};
responseMessage.Headers.Add("WWW-Authenticate", "Bearer");
return responseMessage;
}
}
现在在响应中
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 22
Content-Type: text/plain; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
WWW-Authenticate: Bearer
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcUHJvamVjdHNcVGVzdEFwaVxUZXN0QXBpXGFwaVxUZXN0?=
X-Powered-By: ASP.NET
Date: Fri, 01 May 2015 05:43:51 GMT
You are not authorized
但我仍然每秒请求 500 而不是 401。
谁能阐明这里发生了什么以及如何使其正常工作?
最佳答案
在发送 HTTP header 后,服务器无法附加 header 。
来自响应 500 的错误消息是由一个模块在您的操作执行后尝试将 HTTP header 写入响应流引起的 - 因为您的操作已经写入标题和正文。
通常的罪魁祸首是 FormsAuthentication 和 Owin cookie 身份验证 启动并尝试用 302 替换 401(重定向到登录页面)。
场景:
1. 您的操作已执行 - 添加 header 401 Unauthorized
到 header 集合并将 header 写入响应流,然后将正文(您未授权)写入响应流。
2. FormsAuthenticationModule 在响应 header 集合中看到 401 Unauthorized
header ,并尝试将其更改为 302 Redirect to login page
,并尝试将相应的 header 写入响应流 -失败并显示 Server cannot append header after HTTP headers has been sent.
,因为 header 已经在前面写入。
可能的修复:
1) 如果 FormsAuthenticationModule 在您的请求管道中
- 如果您不使用它,请考虑将其禁用
- 在 .net 4.5 中,您可以通过设置 HttpResponse.SuppressFormsAuthenticationRedirect 来抑制表单例份验证重定向属性为false
- 如果不是在 .net 4.5 上,请考虑使用 HttpModule 来抑制这种重定向
Phil Haack blogged on all the above options .
2) 如果使用 OWIN cookie 身份验证 - 考虑 not setting LoginPath property
关于c# - 带有 Unauthorize 状态代码和 Content//response 的 HttpResponseMessage 没有必需的 WWW-Authenticate header 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29982193/