查看更新以获取更新的问题
我将AFNetworking
'sAFHTTPClient
用于我的应用程序的服务调用。我的服务器使用 HTTP 摘要身份验证进行身份验证。服务调用返回 401 HTTP 错误,WWW-Authenticate
其响应中包含标头作为质询,如下所示:
HTTP/1.1 401
WWW-Authenticate: Digest realm="user@myserver.com",
qop="auth",
nonce="059c37d0e654fdba9c606f35ce84741998"
Content-Type: text/html; charset=utf-8
该connection:didReceiveAuthenticationChallenge:
方法永远不会被调用AFURLConnectionOperation
,这是NSURLConnectionDelegate
在这种情况下,然后会调用我的块集setAuthenticationChallengeBlock:
。相反,我只是得到错误:Error Expected status code in (200-299), got 401
在我的AFHTTPRequestOperation
失败块中。
据我了解,这些是WWW-Authenticate
HTTP 摘要身份验证标头中唯一必需的字段。这与Wikipedia 上此示例中的响应非常相似。我没有任何实际的响应正文,因为无论如何我都没有向用户显示任何 HTML。这应该重要吗?我没有使用不透明字段,但这应该是可选的。我不支持“auth-int”保护质量。除此之外,我不返回Server
或Date
标题。是否需要其中任何一个?
我在这里做错了什么?
更新:我现在正在客户端记录响应标头(Apple 没有提供一种简单打印我知道的纯文本响应的好方法)。如上所示的响应是在服务器上记录的。结果NSHTTPURLResponse
allHeaders
是:
{
"Alternate-Protocol" = "80:quic";
"Cache-Control" = private;
"Content-Type" = "text/html; charset=utf-8";
Date = "Mon, 09 Sep 2013 20:24:00 GMT";
Server = "Google Frontend";
"Transfer-Encoding" = Identity;
Vary = "Accept-Encoding";
"Www-Authenticate" = "Digest realm=\"user@myserver.com\",__ qop=\"auth\",__ nonce=\"f36dc1b8abc342d5c1cbad22a533d3868c\"";
}
Server
和标Date
头实际上包含在服务器以及其他一些标头中。服务器是 Google App Engine。
但问题似乎是我的\r\n
CR+LF 出于某种原因被转换__
为,这弄乱了标题语法。调查这是为什么...
更新 2:仅\n
使用_
. HTTP 要求是使用 CR+LF+SPACE 来分隔标头中的行。所以现在我的问题变成了,如何在我的HttpServletResponse
标题字符串中正确包含这个 CR+LF+SPACE 以便正确编码?服务器响应过程中的编码在哪里被更改,导致_
我得到的字符?
这是创建响应的服务器代码:
public static void sendUnauthorizedResponse(HttpServletResponse resp, String realm, boolean isStale) throws IOException {
String s = ",\r\n ";
String header = "Digest realm=\"" + realm + "\"" + s + "qop=\"auth\"" + s + "nonce=\"" + createNonce() + "\"";
if (isStale) {
header += s + "stale=TRUE";
}
resp.setHeader("WWW-Authenticate", header);
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
log.info("Sent 401 Unauthorized Response:\n" + resp.toString());
}
最后一行是如上所示记录响应的内容,此时格式正确。
回车\r
0x0D 和换行\n
0x0A 都被更改为 ASCII 下划线_
0x5F。
更新 3:我可以确认这不是客户端问题,但一定是由 Google App Engine 服务器引起的。在海报工具中发布服务调用时,我得到了相同的结果。
更新 4:删除 CR+LF 字符并在一行中包含逗号分隔的属性似乎可行,但根据RFC 2047,行的长度不应超过 75 个字符,现在应该是:
'encoded-word' 的长度不得超过 75 个字符,包括 'charset'、'encoding'、'encoded-text' 和分隔符。如果希望编码的文本多于 75 个字符的“编码字”,则可以使用多个“编码字”(由 CRLF SPACE 分隔)。
虽然对多行标题字段的长度没有限制,但包含一个或多个“编码字”的标题字段的每一行被限制为 76 个字符。
所以我仍然需要弄清楚如何正确地将 CR+LF 字符放入我的标题字符串中。
更新 5:因此,似乎HTTP 标头的每行允许的最大字符数取决于服务器,并且可能在数千字节范围内,这对于标头来说应该足够了WWW-Authenticate
。但这仍然没有回答为什么我的标题字符串中的“\r\n”字符被转换为“__”的问题。这是 Google App Engine 中的错误吗?很难想象我是唯一一个使用 CR+LF+SPACE 在 HTTP 响应中的新行上分隔我的标头属性的人。