iphone - 使用 NSURLConnection 正确处理重定向

标签 iphone cocoa cocoa-touch redirect nsurlconnection

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

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

所以我想我需要处理 connection:willSendRequest:redirectResponse:事件NSURLConnection的委托(delegate)并重新附加主体。问题是这条消息的记录似乎严重不足。我能找到的关于此方法的唯一信息是 NSURLConnection Class Reference,这不是很有帮助。除其他外,它包括:

redirectResponse: The URL response that caused the redirect. May be nil in cases where this method is not being sent as a result of involving the delegate in redirect processing.

我不确定这意味着什么。结合初始willSendRequest:调用,我想这就是手段willSendRequest:即使是我的初始请求,在重定向响应之前也会发送。这是正确的吗?

因此,我向我的委托(delegate)添加了代码以保留主体额外的时间,并添加了此 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;
    }
}

这不起作用。但我什至不确定这是否是正确的方法。对我来说这似乎过于黑客化了。我应该做什么?这有记录在任何地方吗?到目前为止,我在 Apple 文档或使用 Google 时没有发现任何有用的信息。

(这是在 iPhone 上,尽管这些类似乎没有太大区别。)

最佳答案

section 10.3.2 of RFC 2616中有一条注释关于此行为:

Note: When automatically redirecting a POST request after receiving a 301 status code, some existing HTTP/1.0 user agents will erroneously change it into a GET request.

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

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

If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

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

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

我使用的是这个:而不是原始问题中的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;
    }
}

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

如果你控制了服务器,那么值得一读RFC 2616, section 10.3完整地查看是否有更好的代码可以使用(当然,同时检查 iOS 是否按应有的方式处理更好的代码)。

您还可以制作重定向请求的可变副本,并将其 HTTP 方法替换为原始请求的 HTTP 方法。相同的一般原则,尽管这有利于让事情不受新请求的影响,而不是旧的请求。在某些情况下,这可能会更好,但我还没有测试过。

关于iphone - 使用 NSURLConnection 正确处理重定向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1446509/

相关文章:

iphone - setStatusBarHidden 然后如何调整应用程序框架大小?

iphone - UITableView 背景作为平铺图像

ios - 本地化自然格式的 API 数据列表

iphone - 如何使用 Phonegap 获取 iPhone 的唯一标识符 (UDID)?

iphone - 从 NSString 到 NSDate 的转换不起作用

macos - 使 NSTableView 单元格只能以编程方式编辑

cocoa - 如何将 NSManagedObject 从一个上下文复制或移动到另一个上下文?

objective-c - CGRect 和 NSRect 之间有什么区别吗?

swift - 构建纯 Swift Cocoa Touch 框架

ios - 在真正的 Apple Watch 上调试 WatchKit - 没有任何反应