IOS 跨域问题分析和处理

一、场景

App混合开发中, IOS 将服务器前端dist包下载到手机应用沙盒目录中,然后通过file:// 协议加载资源,然后前端调用后台api 接口照常走http 接口。

二、问题

当将资源都统一改为file协议加载进来后,去除了混合使用http协议加载资源的load not allowed 问题后,进入登录界面,发现验证码没有出来,刚开始觉得有点不知所然,感觉应该一切都会顺利地走下去,因为安卓平台这边已经走通了,但是问题就是出现了,于是和前端一起排查。

由于IOS 这边的native 端看不到前端的日志信息,所以只能用前端进行alert弹框来显示其信息这种笨拙的方式来调试,于是很费劲,前端那边对于native这边有些概念不清楚,因为在交流过程中需要疏导其理解。

在其调试过程中,我也在想便于调试的方案,后来找到了在ios xcode中能查看console.log日志的方法,其实很简单,就是通过js 和 native 之间的交互,将其转换为nslog 日志输出,这个在混合开发至初期,自己应该就已经尝试过这种交互,只是没有想到作为日志输出来使用:

    //rewrite the method of console.log

            NSString *jsCode = @"console.log = (function(oriLogFunc){\

            return function(str)\

            {\

            window.webkit.messageHandlers.log.postMessage(str);\

            oriLogFunc.call(console,str);\

            }\

            })(console.log);";

            //injected the method when H5 starts to create the DOM tree

            [config.userContentController addUserScript:[[WKUserScript alloc] initWithSource:jsCode injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]];

            [config.userContentController addScriptMessageHandler:self name:@"log"];

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{

    // 输出前端的consolo.log

    NSLog(@"%@",message.body);

}

看其js中的window.webkit.messageHandlers.log.postMessage 这个方法是不是很熟悉? 基本的js和native交互方式。

这样设置完之后,在xcode中就能看到前端页面中的console.log 日志信息了,方便调试。

最终发现原来前端在IOS 这边没有正确地调用native 提供的接口来获取 http 接口的头部 ip+port 信息,导致接口调用就直接走到错误回调中,所以拿不到后台的任何数据,验证码显示不出来。

刚开始以为这就是问题的原因,然鹅too young , too simple.

三、入坑

在前端改完上述问题之后,在日志信息中已经是正确的http 访问url 接口调用了,但是验证码依旧不出来,当看到这个现象的时候,我又丈二的和尚,摸不着头发了,因为安卓平台又是正常的,基于前面出现了前端调用接口不对造成的url 不对的问题,我的主观意识里面仍然觉得是不是前端某些地方还存在差异逻辑,导致IOS这边无法正常调用接口,但是前端确认没有其他差异了,而且之前直接使用http从服务器加载资源的方式也是同样的代码,一切都是正常的。现在只是将资源放到本地通过file加载资源,接口照常还是之前的http调用就出现了问题,不合理。

几番定位排查之后,仍然不得要领,过程中也开始怀疑是不是跨域的问题,但是日志信息并不明显,自己对此概念的理解也不太明了。

在此过程中还发现了一个现象就是:前端直接使用常规的http请求直接访问后台能正常拿到结果,但是其业务逻辑中需要对请求进行二次保证处理,在头部增加信息或者其他参数,拦截统一对返回结果进行处理,经过这种包装的请求就无法正常访问。

最终,我想还是通过fiddler抓包拦截再看看,于是看到下面的结果:

直接写死的http请求正常访问的:

通过包装后不能正常访问的:

前端发出的都是GET 请求,但是为什么经过包装之后,请求变成OPTIONS 了呢?

刚开始我以为请求就只有 POST  GET PUT DELETE 这几种,现在又冒出了这个,所以开始在网上查找相关信息,最后被引导到了跨域问题。

尤其是这个:nginx 跨域踩坑及解决--OPTIONS请求处理 | LongSheng

OPTIONS请求方法的主要用途有两个:

1、获取服务器支持的HTTP请求方法;

2、用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。

再来看下这个“某些情况下”都是什么情况?

1、跨域请求,非跨域请求不会出现options请求
2、自定义请求头
3、请求头中的content-type是application/x-www-form-urlencoded,multipart/form-data,text/plain之外的格式

当满足条件12或者13的时候,简单的ajax请求就会出现options请求,有没有感觉到一点同源策略的意思,个人理解这个就是浏览器底层对于同源策略的一个具体实现。首先得到服务器端的确认,才能继续下一步的操作,这也是为什么options请求也被叫做“预检”请求的原因吧。

这段描述我感觉就和我遇到的问题一模一样,写死的http请求直接访问可以,这应该就是简单请求,包装之后的不行,就是里面描述的触发OPTIOS预检请求。

ajax跨域,这应该是最全的解决方案了 - 掘金

期间根据网上的各种方案进行了各种尝试,nginx 配置:

if ($request_method = 'OPTIONS') {     

add_header 'Access-Control-Allow-Origin' '*';     

add_header 'Access-Control-Allow-Methods' 'GET, POST,PUT,DELETE,OPTIONS';     add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';     add_header 'Access-Control-Max-Age' 3600;     

add_header 'Content-Type' 'text/plain charset=UTF-8';   

 add_header 'Content-Length' 0;   

return 204;

}

在后台返回头里面增加各种信息,最终都是没有效果,感觉问题找到了,但是就是无法解决,濒临崩溃,甚至想到了是否要拦截然后由IOS这边直接访问后台在返回结果这前端这种机制。

四、破局

今天早上起来在上厕所的时候还在想着这个问题要怎么处理,当我蹲在茅坑上思索的时候,又在想为什么安卓会正常呢,突然灵光一闪,我似乎看到了几行代码,对了,安卓这边之前在webview的设置中加过允许跨域的处理,是不是那几行代码有效果。于是早上来到办公室就开始尝试,刚开始加了一行代码:

[config.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];

调试后发现还是没有效果,但是我隐约从这个key的名称中来看,就是针对本地文件访问跨域的处理。

于是先到安卓端将那段代码屏蔽来进行假设验证,发现屏蔽后安卓果然也不正常了,这下心里已经有一定把握了,最终再加一个设置代码到ios wkwebview中:

     //允许跨域

        [config.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];

        if (@available(iOS 10.0, *)) {

            [config setValue:@YES forKey:@"allowUniversalAccessFromFileURLs"];

        }

验证码终于出现了,这几个图片字母终于跃然屏上。心中释然,对茅塞顿开这个成语的理解再次升级,茅房顿悟真的很有效果,在我十年的工作生涯中,我感觉有好多次的问题都是在不经意间想到了解决方案,打水的时候,蹲坑的时候,窗口远眺的时候,念念不忘,必有回响,放松放空,一切皆通。

其实这个问题还是在过程中被带偏了,认为手机端的webview 相当于浏览器,然后解决跨域问题应该都是从前后端的配置去解决,没有想过去改浏览器来处理。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ArcGIS REST API是Esri公司提供的一种基于HTTP/HTTPS协议的Web API,用于访问和管理ArcGIS Server和ArcGIS Online等GIS服务和资源。ArcGIS REST API支持多种编程语言和平台,例如Java、Python、JavaScript、.NET、iOS和Android等。以下是ArcGIS REST API的一些主要特点和功能: 1. 支持多种HTTP操作:ArcGIS REST API支持多种HTTP操作,例如GET、POST、PUT和DELETE等,可以用于从GIS服务中获取或修改数据。 2. 支持多种数据格式:ArcGIS REST API支持多种数据格式,包括JSON、XML、HTML和二进制等,可以根据需要选择合适的数据格式。 3. 支持多种GIS服务和资源:ArcGIS REST API支持多种GIS服务和资源,例如地图服务、要素服务、空间分析服务、地理编码服务、地理处理服务、Web地图和Web应用程序等。 4. 支持数据查询和过滤:ArcGIS REST API支持对GIS服务中的数据进行查询和过滤,可以根据要求返回符合条件的数据。 5. 支持安全认证和授权:ArcGIS REST API支持多种安全认证和授权方式,例如基本认证、令牌认证和OAuth2.0认证等,可以保证GIS服务和资源的安全性和可靠性。 6. 支持跨域访问:ArcGIS REST API支持跨域访问,可以在不同的域名和网站之间进行数据交互和共享。 7. 支持自定义扩展:ArcGIS REST API支持自定义扩展,可以根据需要扩展和定制GIS服务和资源的功能和特性。 总之,ArcGIS REST API是Esri公司提供的一种基于HTTP/HTTPS协议的Web API,用于访问和管理ArcGIS Server和ArcGIS Online等GIS服务和资源,具有多种特点和功能,可以满足不同用户的需求和要求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值