使用NSURLConnection正确处理重定向 [英] Handling redirects correctly with NSURLConnection

查看:212
本文介绍了使用NSURLConnection正确处理重定向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为此,我要假装原始网址是 http:// host / form ,新网址是 https:// host / form 。 (注意,在我发送之前,两个URL都是安全的,但是,不安全的安全似乎是一个方便的重定向来测试这个。)

For the purposes of this, I'm going to pretend the original url is http://host/form and the new url is https://host/form. (Note that before I ship this, both URLs are going to be secure. However, the nonsecure-to-secure seems like a convenient redirect to test this on.)

我正在使用重定向我的 NSURLConnection 访问Web API。基本上,我想把我刚刚提交到 http:// hostaform 的所有东西,然后重新提交到 https:// host / form 。我认为这将是默认行为,但它看起来像身体在重定向丢失。

I'm accessing a web API using NSURLConnection that redirects me. Basically, I want to take everything I just submitted to http://hostaform and re-submit it to https://host/form. I thought this would be the default behavior, but it looks like the body is being lost in the redirect.

所以我想我需要处理 connection:willSendRequest:redirectResponse:事件 NSURLConnection 的代理并重新附加正文。问题是这个消息似乎被遗忘欠妥。我可以在此方法上找到的唯一信息是 NSURLConnection类参考,这不是非常有帮助。其中包括:

So I think I need to handle the connection:willSendRequest:redirectResponse: event of the NSURLConnection's delegate and re-attach the body. The problem is this message seems woefully underdocumented. The only info I can find on this method is NSURLConnection Class Reference, which isn't very helpful. Among other things, it includes this:

redirectResponse :引起重定向的URL响应。如果此方法不是由于在重定向处理中涉及委托的结果而发送的,则可能是nil。
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:即使对于我的初始请求,之前的重定向响应。这是正确的吗?

I'm not sure what this means. Combined with an initial willSendRequest: invocation, I think this is means willSendRequest: is being sent even for my initial request, prior to the redirect response. Is that correct?

所以我已经添加了代码给我的代理,保留了一个额外的时间,并添加了 willSendRequest:处理程序:

So I've added code to my delegate to retain the body an extra time, and added this willSendRequest: handler:

- (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;
    }
}

但我甚至不确定这是否是正确的方法。对我来说似乎过于迷茫。我应该怎么办?这是记录在任何地方吗?我发现没有什么有用的苹果的文档或使用谷歌到目前为止。

It doesn't work. But I'm not even sure if this is the right approach. It seems excessively hackish to me. What should I be doing? Is this documented anywhere? I've found nothing useful in Apple's documentation or using Google so far.

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

(This is on the iPhone, although there doesn't seem to be much difference in these classes.)

推荐答案

RFC 2616的第10.3.2节关于此行为:


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

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 ,并且会丢失有效载荷。

So this behaviour seems to be non-standard but historical. That GET request is not a POST, and it'll be missing the payload.

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

Interestingly enough, this is also in the same section:


如果接收到301状态代码到一个请求其他
比GET或HEAD,用户代理不能自动重定向
请求,除非它可以被用户确认,因为这可能
更改请求的条件发布。

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.

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

That's pretty clear and seems to indicate we can't fix this, but I think ignoring this for the purpose of our own web service clients for services we pick (or control) is probably the least bad alternative.

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

So how do we solve this?

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

Instead of the willSendResponse: in the original question, I'm using this:

- (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发送给我。

The idea here is that instead of cloning the new request and trying to shape it the same as the one Cocoa Touch sends me, I create a clone of the original request and change just the URL to match the request Cocoa Touch sent me. That original request is still a POST with the payload attached.

如果你控制服务器,值得读取 a href =https://tools.ietf.org/html/rfc2616#section-10.3 =nofollow noreferrer> RFC 2616,第10.3节,以了解是否有更好的代码可以使用(当然,检查,当然,iOS处理更好的代码,因为它应该)。

If you control the server, it's worth reading RFC 2616, section 10.3 in its entirety to see if there's a better code you can use (while checking, of course, that iOS handles the better code as it should).

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

You could also make a mutable copy of the redirected request and replace its HTTP method with the HTTP method of the original request. Same general principle, though that would favour keeping things from the new request rather than the old. In some circumstances that might work better, but I haven't tested this yet.

这篇关于使用NSURLConnection正确处理重定向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆