背景

在源网页经过服务器重定向打开某个三方网页,网络层呈现了 -1005 (NSURLErrorNetworkConnectionLost) 错误码,排查差异后发现是因为给这个三方服务带了源网页特有的 HTTP Header,导致服务器检查异常然后断开衔接。

核心原因是跨域重定向场景透传了 Header 带到了三方服务,这有些不符合常理,会带来两个明显的问题:

  • 敏感 HTTP Header 传递给三方服务,存在隐私安全问题;
  • 服务收到未预期的 HTTP Header,可能被视为不合法拜访,导致网页异常;

系统库怎么规划的

NSURLSession 在跨域重定向场景默许会透传 HTTP Header,参阅 Swift 在 _HTTPURLProtocol 的相关处理:

    /// If the response is a redirect, return the new request
    /// RFC 7231 section 6.4 defines redirection behavior for HTTP/1.1
    /// - SeeAlso: <https://tools.ietf.org/html/rfc7231#section-6.4>
    func redirectRequest(for response: HTTPURLResponse, fromRequest: URLRequest) -> URLRequest? {
        //TODO: Do we ever want to redirect for HEAD requests?
        guard
            let location = response.value(forHeaderField: .location),
            let targetURL = URL(string: location)
            else {
                // Can't redirect when there's no location to redirect to.
                return nil
        }
        var request = fromRequest
        // Check for a redirect:
        switch response.statusCode {
            case 301...302 where request.httpMethod == "POST", 303:
                // Change "POST" into "GET" but leave other methods unchanged:
                request.httpMethod = "GET"
                request.httpBody = nil
            case 301...302, 305...308:
                // Re-use existing method:
                break
            default:
                return nil
        }
        // If targetURL has only relative path of url, create a new valid url with relative path
        // Otherwise, return request with targetURL ie.url from location field
        guard targetURL.scheme == nil || targetURL.host == nil else {
            request.url = targetURL
            return request
        }
	 (后面是相对路径处理)
    }

大致处理流程为:

  • 取出响应头 Location 字段作为方针 URL;
  • 若为 POST 恳求改为 GET 恳求并清空其 Body;
  • 若方针 URL 为相对路径,补齐完整 URL;

能够看到重定向后的恳求会直接继承 HTTP Header,这个处理遵循了 RFC 7231 的标准,大致去翻了一下,只描述了 Location header field 的处理办法,而没有说明其它恳求头该怎么处理,在 Chrome 下重定向场景应该是直接丢掉之前的 Header 的。

我们知道有一个揭露署理办法…willPerformHTTPRedirection…能够去改变重定向恳求,但假如不借助网络阻拦技能,WebKit 里边的恳求也无法修正,趁便看一下 WebKit 内部是否对这种场景有所处理。

WebKit 是在 NetworkSessionCocoa 类里边承载 NSURLSession 恳求的,实现了URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:协议,顺着处理链路从 Network 进程跟到 Web 进程再跟到 APP 进程,都没有找到关于跨域重定向整理 HTTP Header 的处理,更不用说揭露配置才能了。

解决计划

针对 WebView 需求跨域重定向的场景,怎么防止私有 HTTP Header 传递给方针恳求服务?

计划一

假如前置恳求是为了做计算上报,那能够直接跳转到方针 URL,前置恳求旁路去处理;假如前置恳求是为了获取跳转的地址,那么能够建议一个 Ajax 恳求拿到回包后去跳转方针 URL。

或者更直接的,把 server-side redirect 改为 client-side redirect,让前置恳求回来文档,文档内部进行document.replace()等函数跳转到方针 URL,但这种处理会让性能劣化,并且会导致前置恳求相关的 Web 进程前史栈缓存被整理(参阅:www.jianshu.com/p/af67ed9af…

核心思想就是防止服务器跨域重定向,因为和 Chrome 内核表现不一致且前端改造本钱较大,一般较难施行,但这关于没有 WebKit 网络阻拦技能的 APP 来说可能是仅有思路。

计划二

假如有 WebKit 网络阻拦技能,那处理就比较简单了,只需求确保在重定向恳求建议之前,假如主域名发生变化,就把 APP 私有的恳求头整理掉,较简单的躲避系统规划问题。