背景
在源网页通过服务器重定向打开某个三方网页,网络层出现了 -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 进程历史栈缓存被清理
核心思想就是避免服务器跨域重定向,由于和 chrome 内核表现不一致且前端改造成本较大,一般较难实施,但这对于没有 webkit 网络拦截技术的 app 来说可能是唯一思路。
方案二
如果有 webkit 网络拦截技术,那处理就比较简单了,只需要保证在重定向请求发起之前,如果主域名发生变化,就把 app 私有的请求头清理掉,较简单的规避系统设计问题。
以上就是nsurlsession跨域重定向透传http header问题解决的详细内容,更多关于nsurlsession跨域重定向的资料请关注代码网其它相关文章!
发表评论