【问题标题】:ASIHttpRequest responseStatusCode = 200. But not getting right responseData from serverASIHttpRequest responseStatusCode = 200。但没有从服务器获得正确的 responseData
【发布时间】:2012-05-06 00:11:29
【问题描述】:

全部

这是一个很少发生的问题。事实上,我不得不花费大量时间来重现它,但无论如何都在这里。

我正在使用 ASIHTTPRequest 从我的服务器获取一些数据。除了具有 responseStatusCode == 200 的那些之外,我会抛出任何错误。我的服务器返回一些消息。

我注意到的是,有时,根据我的无线连接(在笔记本电脑模拟器的使用情况下),需要身份验证的连接,ASIHttpRequest 返回 200 的响应,但 responseData 类似于以下内容,而不是来自我的服务器的消息

<HTML><HEAD><TITLE>Cisco Systems Inc. Web Authentication Redirect</TITLE><META http-equiv="Cache-control" content="no-cache"><META http-equiv="Pragma" content="no-cache"><META http-equiv="Expires" content="-1"><META http-equiv="refresh" content="1; URL=https://webauth-redirect.oracle.com/login.html?redirect=17.22.111.222/scripts_dummy/messagesx.php"></HEAD></HTML>

这是正确的吗?如果未收到来自服务器的消息,则 responseStatusCode 不应为 200 以外的值

我该如何处理这种情况?检查 responseStatusCode == 200 后的意思似乎还不够好。这只是一个例子。在其他无线区域,打印出不同的垃圾。

更新 不确定这是否有任何作用,但我有

request.shouldUseRFC2616RedirectBehaviour = YES; // where request is ASIHTTPRequest

【问题讨论】:

    标签: iphone objective-c xcode http asihttprequest


    【解决方案1】:

    这不是ASIHTTPRequest 或您的客户端代码的错。那是服务器期望客户端是 Web 浏览器并向其发送元刷新重定向(即,其中嵌入了重定向的 HTML 页面)而不是 HTTP 30xASIHTTP 会为您处理。

    这是一个很好的例子,说明元刷新是如何被滥用的:它原本是用来刷新当前页面的,但人们开始使用它来将客户端发送到其他地方,而这正是 HTTP 30x 的设计初衷。谷歌搜索“元刷新与 301 重定向”会给你大量的博客文章来争论。

    在您的情况下,除非您可以让您的服务器对非浏览器客户端表现得更友好,否则您需要在响应代码为 200 时自己检查这种情况,解析重定向并自己重新发出请求。

    【讨论】:

    • 非常感谢您的回复。当您说“您需要自己检查这种情况”时,您是否知道我如何使用 ASIHTTPRequest 来做到这一点?
    • 请求的结果(您可能知道)在request.responseString 中 - 您需要在该字符串中搜索http-equiv="refresh" 并向URL= 中的目的地发出一个新的ASIHTTPRequest .
    • 好吧,我不太喜欢那个解决方案。看起来像一个黑客。我在想的是在响应头中从服务器发送一个特殊的键/值对。说 header('My App:' . 'success');然后检查 ASIhttpRequest 的 responseHeaders 中是否存在该键/值对。这样我就应该永远安全?
    • 如果可以控制服务器,只需发送301!如果您无法控制服务器,则不确定我是否在关注您。
    【解决方案2】:

    在考虑了几次之后,我想出了一个替代策略。内容类型将被保留,不应混淆。

    您应该能够将内容类型用作您正在接收代理注入页面的标志。设置内容类型参数,然后让您的应用程序关闭该参数。任何没有参数的响应都是无效的。

    $content_type = 'text/html; FooCorp-MyApp=true'
    

    顺便说一句:如果您不正确支持 HTML 处理,为什么要使用 text/html 的内容类型。元刷新应该是任何 HTML 引擎的一部分。如果您不需要 HTML,您可能需要考虑使用特定于数据的内容类型,例如 XML、YAML 或 JSON。


    问题已经提出,“这有效吗?”

    来自RFC 2616: 3.7 Media Types

    类型、子类型和参数属性名称不区分大小写。参数值可能区分大小写,也可能不区分大小写,具体取决于参数名称的语义。线性空白 (LWS) 不得在类型和子类型之间使用,也不得在属性与其值之间使用。参数的存在与否可能对媒体类型的处理很重要,具体取决于媒体类型注册表中的定义。

    请注意,一些较旧的 HTTP 应用程序无法识别媒体类型参数。当向旧的 HTTP 应用程序发送数据时,实现应该只在该类型/子类型定义需要时使用媒体类型参数。

    对我来说,这样做的好处是不要向老客户发送非标准参数。在上下文中,如果您将其发送给自 2000 年以来的任何客户,这意味着您是安全的。

    【讨论】:

    • 感谢您的回复。现在我有机会投票并标记这是正确的。根据您之前的 cmets,您应该得到它。你是对的,我应该将内容类型设置为“application/json”,因为这就是我所期望的。所以现在作为最终解决方案,我将同时执行 $content_type = 'application/json; FooCorp-MyApp=true' 和客户头文件并进行 OR 检查。那样我应该是最安全的。不过有一个问题……可以将未注册的 FooCorp-MyApp=true 放入内容类型中吗?
    • 我更新了我的答案。顺便说一句:只检查“应用程序/json”就足够了。如果代理发送内容类型为“application/json”的 HTML 文档,代理将是一个真正的混蛋。
    【解决方案3】:

    我最终在响应标头中传递了一个特殊的键/值对,以确保客户端了解响应来自我的服务器,而不是来自某些中间重定向。

    function sendResponse($status = 200, $body = '', $content_type = 'text/html')
    {
       $status_header = 'HTTP/1.1 ' . $status . ' ' . getStatusCodeMessage($status);
       header($status_header);
       header('Content-type: ' . $content_type);
       $value = 'success';
       header('myApp:' . $value); // --> I will always check in my client that the key myApp has the value success
    
    echo $body;
    }
    

    【讨论】:

    • 此解决方案将来可能会给您带来问题。一些代理过滤掉未知的标头。除非您对网络环境有严格的控制,否则您不能总是依赖自定义标头。
    • 此外,您应该始终以“x-”开头的非标准标题。像“x-MyApp:”这样的东西。 $value 会做得很好。
    • 是的。您可以提出更清洁的替代方案吗?
    • X- 也被弃用了。见stackoverflow.com/questions/3561381/…
    • WTF:draft-ietf-appsawg-xdash-05 是一场噩梦。他们的答案是因为糟糕的实现而污染了全局命名空间。附录 B 指出了愚蠢之处。我想我仍然会遵循建议并使用“FooCorp-MyApp”(其中 FooCorp 是您的公司名称)。
    猜你喜欢
    • 2014-06-20
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2018-12-21
    • 2021-12-15
    • 2012-01-22
    • 1970-01-01
    相关资源
    最近更新 更多