使用NSURLConnection正确处理重定向

Ste*_*her 25 iphone cocoa redirect cocoa-touch nsurlconnection

出于这个目的,我将假装原始网址http://host/form和新网址https://host/form.(请注意,在我发送之前,这两个URL都是安全的.但是,非安全到安全似乎是一个方便的重定向来测试它.)

我正在使用NSURLConnection重定向我来访问Web API .基本上,我想把我刚刚提交的所有内容都http://hostaform重新提交给https://host/form.我认为这将是默认行为,但看起来身体在重定向中丢失了.

所以我认为我需要处理代表的connection:willSendRequest:redirectResponse:事件NSURLConnection并重新附加身体.问题是这个消息看起来很糟糕.我可以在这个方法上找到的唯一信息是NSURLConnection类参考,这不是很有用.除其他外,它包括:

redirectResponse:导致重定向的URL响应.如果由于在重定向处理中涉及委托而未发送此方法,则可能为零.

我不确定这意味着什么.结合初始willSendRequest:调用,我认为这是willSendRequest:在重定向响应之前,即使是我的初始请求也会发送的方法.那是对的吗?

所以我已经为我的委托添加了代码以保留正常的时间,并添加了这个willSendRequest:处理程序:

- (NSURLRequest *)connection: (NSURLConnection *)inConnection
             willSendRequest: (NSURLRequest *)inRequest
            redirectResponse: (NSURLResponse *)inRedirectResponse;
{
    if (inRedirectResponse) {
        NSMutableURLRequest *r = [[inRequest mutableCopy] autorelease];
        [r setURL: [inRedirectResponse URL]];
        [r setHTTPBody: body];
        return r;
    } else {
        return inRequest;
    }
}
Run Code Online (Sandbox Code Playgroud)

它不起作用.但我甚至不确定这是否是正确的方法.这对我来说似乎过于苛刻.我该怎么办?这记录在哪里?到目前为止,我发现Apple的文档或使用Google没有任何用处.

(这是在iPhone上,虽然这些类似乎没有太大区别.)

Ste*_*her 38

RFC 2616的第10.3.2节中有关于此行为的注释:

注意:在收到301状态代码后自动重定向POST请求时,某些现有HTTP/1.0用户代理会错误地将其更改为GET请求.

所以这种行为似乎是非标准的,但却是历史性的.该GET请求不是a POST,它将丢失有效负载.

有趣的是,这也在同一部分:

如果收到301状态代码以响应GET或HEAD以外的请求,则用户代理不得自动重定向请求,除非用户可以确认,因为这可能会改变发出请求的条件.

这很清楚,似乎表明我们无法解决这个问题,但我认为为了我们自己的Web服务客户端而忽略这一点,我们选择(或控制)的服务可能是最不好的选择.

那么我们如何解决这个问题呢?

而不是willSendResponse:在原始问题中,我使用这个:

- (NSURLRequest *)connection: (NSURLConnection *)connection
             willSendRequest: (NSURLRequest *)request
            redirectResponse: (NSURLResponse *)redirectResponse;
{
    if (redirectResponse) {
        // we don't use the new request built for us, except for the URL
        NSURL *newURL = [request URL];
        // Previously, store the original request in _originalRequest.
        // We rely on that here!
        NSMutableURLRequest *newRequest = [_originalRequest mutableCopy];
        [newRequest setURL: newURL];
        return newRequest;
    } else {
        return request;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的想法是,不是克隆新请求并尝试将其形状与Cocoa Touch发送给我的相同,而是创建原始请求的克隆并仅更改URL以匹配Cocoa Touch发送给我的请求.原始请求仍然POST附有有效载荷.

如果您控制服务器,则值得阅读RFC 2616,第10.3节,以查看是否有更好的代码可供使用(当然,检查时iOS会处理更好的代码).

您还可以制作重定向请求的可变副本,并将其HTTP方法替换为原始请求的HTTP方法.同样的一般原则,虽然这有利于保持新请求而不是旧请求.在某些情况下可能会更好,但我还没有测试过.

  • 你说"而不是willSendResponse:",但在URLConnection中没有这样的东西.您的答案与上面的内容类似,除非您将URL发送到原始内容?并且您在mutableCopy中引用了请求,该请求未在任何地方声明.答案非常混乱. (3认同)
  • 我想指出,通过复制原始请求,将复制包含授权标头的原始标头.对我来说,我的原始请求需要基本身份验证,但重定向请求不需要任何身份验证,因此我必须对复制原始请求更加明智.结果是400级错误. (2认同)

小智 13

您应该检查服务器发送的HTTP响应状态代码,以确定是发送GET还是重复POST.对于303(或302),发送GET请求.对于307,重复POST.