摘要: 跨域问题是web开发领域一个常见的问题,相信每个web开发者都遇到“跨域”的问题

最近公司的iOS开发任务比较少,所以自己最近开始了Web开发的任务,在用H5做了很多页面,所做的东西和之前客户端界面一模一样,只是做好h5搬到微信上。本人开发环境:html开发ide一会用HBulder一会儿用Sublime。

235815_vhrw_1778933.png

为了模拟真实的环境,所以HBulder新建了WebApp,跑起来可以针我的大玫瑰金上运行看效果(iphone6s plus玫瑰金)。我很傻的以为手机上运行没错就没问题了,不会存在传说中的跨域问题,没想到周五下午要合并代码到Dev分支,才发现合并进去页面报错。

235833_q0iv_1778933.png

只能怪自己"too young too naive",回头一想,原来App请求接口类似于C/S不存在跨域问题。而网页这种方式只要协议、域名、端口、有一个不一致就会导致跨域,由于自己所做的页面有40多,所以改起来烦的要死,问同事除了将数据放进url后来形成类似http://xxx/com?s=xx&q=yy这种形式有木有其他办法?最后找出一种快速修改的方法,见下面代码

修改前

$.ajax({

type: "post",

url: early_children_url ,

data:urlJson,

success: function(data) {

console.log(storageData);

swal({

//省略...

修改后

var neonataldetail = '{' +

'"babyinfoid":"' + earlyBabyInfoId + '",' +

'"days":"' + day + '",' +

'"feedingtimes":"' + feedingtimes + '",' +

'"feedingway":"' + feedingway + '",' +

'"stoolfrequency":"' + stoolfrequency + '",' +

'"urinate":"' + urinate + '",' +

'"yellowish":"' + yellowish + '",' +

'"weight":"' + weight + '"' +

'}';

var dataJson = {

"type": early_children_perinatal_type,

"neonataldetail": JSON.parse(neonataldetail)

};

var urlJson = JSON.stringify(dataJson);

$.ajax({

dataType: "jsonp",

type: "post",

url: early_children_url + "?s=" + urlJson,

success: function(data) {

console.log(storageData);

swal({

title: "提交成功",

text: "",

showCancelButton: false,

closeOnConfirm: false,

showLoaderOnConfirm: true

}, function(data) {

window.location.href = "early-children.html";

});

},

error: function() {

swal("上传失败,请检查网络后重试");

}

});

最后查了相关的资料发现跨域问题大体有3种解决方案:(1)、代理;(2)、JSONP(支持get请求);(3)、XHR2;(4)、CORS跨域资源共享;(5)、通过修改document.domain来解决iframe跨域问题;(6)、window.name进行跨域;(7)、HTML5的window.postMessage方法

具体说明:基于浏览器的安全考虑,由于同源策略的限制,不同域名、不同端口、不同协议的对象不能互相调用。(其实浏览器成功发送请求并拿回了数据 只是浏览器的同源策略 禁止了获取 )

代理:通过统一域名下的Web服务器创建一个代理。

举例说明:www.hangzhou.com的a.html需要调用www.shanghai.com下的b.php服务,显然这违反了同源策略,所以就需要通过代码这个方法去解决问题。具体怎么做?可以在www.hangzhou.com下可以写个exchange.php。将去请求www.shanghai.com下的服务,之后将结果返回给a.html。这样访问www.hangzhou.com/exchange.php的效果等于访问www.shanghai.com的服务

JSONP:JSON with padding。是JSON的一种使用方式,适用于主流浏览器的跨域访问问题。JSONP由2部分组成:回调函数和数据

//www.hangzhou.com

js文件载入成功后会执行我们在url参数中指定的函数,所以JSONP是需要服务端进行配合的。

//www.shanghai.com

XHR2:HTML5提供的XMLHttpRequest Level2已经实现了跨域访问以及其他的一些新功能。但不适配所有浏览,比如IE10以下的版本均不支持。

此外还需要在服务端修改

header('Access-Controller-Allow-Origin:*');

header('Access-Controller-Allow-Methods:POST、GET');

window.onload = function () {

var xhr = new XMLHttpRequest();

//判断浏览器是否支持XHR2

if (xhr.withCredentials === undefined) return false;

xhr.open("get", "http://www.baidu.com");

xhr.onreadystatechange = function () {

if (xhr.readyState !== 4) return;//忽略未完成的调用

if (xhr.status === 200) {

   console.log(xhr.responseText);

}

}

xhr.send(null);

}

CORS跨域资源共享:Cross-Origin Resource Sharing定义了进行访问跨域资源时浏览器如何与服务器通信。

如果使用CORS

代码与之前的代码差别就是使用了绝对路径。服务端对于CORS的支持在于Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。

CORS和JSONP对比

1、JSONP只可以实现get请求,CORS可以所有类型的HTTP请求

2、CORS开发者可以使用普通的XMLHTTPRequest请求和获取数据

3、JSONP支持较老的浏览器,而老版本的浏览器不支持CORS

通过修改document.domain来跨域

浏览器的同源策略限制之一就是不能通过Ajax去请求不同源的文档,限制之二就是浏览器中不同域的框架之间是不能进行js交互。

不同框架之间可以获取window对象,但是window对象的属性和方法不可获取到。

http://www.hangzhou.com/a.html的一个frame的src是http://www.xihu.hangzhou.com/b.html这时候document.domain就可以上场了,

不过需要注意,document.domain的设定有限制,必须设置成自身或比自身更高一级的父域,且主域必须相同。

在页面http://xihu.hangzhou.com/b.html也需要设置

通过window.name来跨域

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的

HTML5的window.postMessage方法跨域

window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。

传送门:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy、http://www.ruanyifeng.com/blog/2016/04/cors.html

小礼物走一走,来简书关注我

赞赏支持

web端开发 © 著作权归作者所有 举报文章

关注杭城小刘

写了 24473 字,被 38 人关注,获得了 57 个喜欢

iOS开发、web开发 | 95后 | 海贼王、龙珠 | 乒乓球 健身 | 杭州 https://fantasticlbp.gitbooks.io/knowledge-kit/content/

喜欢 5 更多分享

9条评论 只看作者 按时间倒序按时间正序

左岸__

3楼 · 2018.06.13 08:45

不存在跨域 那么我们后台让我每次接口请求都传递cookie 给他 然后他才能拿到具体的某个用户 如果我不传cookie 那么关于用户的信息就拿不到

大神觉的 我不传cookie 别的方式能拿到吗

赞 回复

杭城小刘: @左岸__ HTTP是无状态的协议,也就是说用户与服务器握手之后建立一个连接了,之后服务器不记得你干了什么事情,这时候就需要session保持用户都干了什么(比如用户成功登录了购物网站,之后他点击加入商品A,然后基于推荐系统,可能将商品B加入到了购物车,最后在结算的时候服务器不知道你干了什么,对于这种情况就需要 session 了,服务端将 session 有关的信息返回给客户端,客户端保存 session 的一些信息到 cookie中)。所以只要实现这个原理都可以,换个方法传递,比如说将信息保存到 LocalStorage 和 SessionStorage 里面,然后顺着接口传递给后台,当然这是最 low 的做法。最好还是研究下 cookie ,用 cookie 传递过去

2018.06.13 09:00 回复

左岸__: @杭城小刘 只要实现这个原理都可以,换个方法传递,比如说将信息保存到 LocalStorage 和 SessionStorage 里面,然后顺着接口传递给后台

有这么一个疑问 就是 我如果用AFN请求的话 他是默认帮我存储这个cookie的对吧 之后我在请求首页 或者别的接口的数据时 AFN发起的请求头里 会自动携带这个session 但是session会有一个过期时间限制 所以在每次程序启动的函数didFinishLaunchingWithOptions里在走一遍请求登录的接口 用来更新session 然后 每次发所有接口的请求前判断下session是否过期 过期了提示 然后跳转登录

这么做可不可以?这么做相当于我没直接接触session cookie

我想像中的方式是 登录成功之后 返回个userID 然后每次我传递这个useid来判定具体用户 会更直接了当 我感觉我们后台整这个session cookie的整的我很不明白

2018.06.13 14:55 回复

左岸__: @左岸__ session会有一个过期时间限制

所以第一:在每次程序启动的函数didFinishLaunchingWithOptions里在走一遍请求登录的接口 用来更新session

第二:每次发所有接口的请求前判断下session是否过期 过期了提示 然后跳转登录

2018.06.13 14:57 回复

添加新评论 还有2条评论, 展开查看

左岸__

2楼 · 2017.08.31 19:28

我现在后头的接口返回的是jsonp

而不是json

我用AFN请求Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}

大神之见 我该怎么拿到数据.......

赞 回复

杭城小刘: @左岸__ 跨域只针对web端开发才存在,跨域是浏览器同源策略造成的,客户端不存在跨域问题,应该是你解析数据出错了

2017.08.31 19:31 回复

左岸__: @杭城小刘 奥 我这么写好像可以了

NSURLSession *session = [NSURLSession sharedSession];

NSURL *url = [NSURL URLWithString:@""];

[[session dataTaskWithURL:url

completionHandler:^(NSData *data,

NSURLResponse *response,

NSError *error) {

// handle response

if (data) {

NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"stringJSONed: %@",jsonString);

//Do something with the received jsonString, just like in @ rmaddy's reply

} else {

NSLog(@"Error loading data: %@", error);

}

}] resume];

return;

2017.08.31 19:54 回复

添加新评论

作者:杭城小刘

链接:https://www.jianshu.com/p/859d9098305c

來源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

一个iOS程序员眼中的跨域问题的更多相关文章

  1. 混合开发的大趋势之 一个Android程序员眼中的 React.js 块级作用域 和 let

    转载请注明出处:王亟亟的大牛之路 最近都有事干然后,快到月底了这个月给CSDN的博文也就两篇,想想也蛮多天没更了,那就来一篇. 老规矩,先安利:https://github.com/ddwhan012 ...

  2. 混合开发的大趋势之 一个Android程序员眼中的 React.js 箭头函数,const, PropTypes

    转载请注明出处:王亟亟的大牛之路 昨天写了篇React.js的开头之作,讲了讲块级作用域和let,先安利:https://github.com/ddwhan0123/Useful-Open-Sourc ...

  3. iOS程序员对算法的要求

    算法和数据结构(鉴于二者的关联,以下统称算法),对于程序员的重要性一直是个具有争议性的话题.有一些程序员内心对算法有着天然的排斥,面试当中一旦考察算法知识,会被不少程序员吐槽,但有部分公司又一直在坚持 ...

  4. 程序员眼中的 SQL Server-执行计划教会我如何创建索引?

    先说点废话 以前有 DBA 在身边的时候,从来不曾考虑过数据库性能的问题,但是,当一个应用程序从头到脚都由自己完成,而且数据库面对的是接近百万的数据,看着一个页面加载速度像乌龟一样,自己心里真是有种挫 ...

  5. iOS 程序员 6 级考试(答案和解释)

    iOS 程序员 6 级考试(答案和解释)   我是前言 1. 下面的代码分别输出什么? @implementation Son : Father- (id)init { self = [super i ...

  6. 写给iOS程序员的命令行使用秘籍

    http://www.jianshu.com/p/44d3b8f713f2 Mac OS是Unix系统的分支,有着强大的命令行功能.很多事情在命令行下处理会事半功倍,所以我就iOS程序员可能会用到的功 ...

  7. H5 App如此强悍,要降薪的恐怕已不只是iOS程序员

    2015年的最后几天,移动开发圈里最为火爆的话题之一无疑是“iOS程序员月薪降至12K”这则报道. 有人认为这是O2O创业遇冷所致,也有人认为这是iOS生态过于封闭致使智能硬件等新领域对iOS开发者的 ...

  8. 同样级别iOS程序员,为啥比我菜的程序员薪资都比我高?

    前言: 作为程序员,都有一种相同的焦虑——即当一次又一次的新技术浪潮袭来,总会不由自主的拼命跟随,总是担心如果不紧跟新技术的潮流,将会被时代所抛弃. 害怕年龄,害怕平庸,其实只是你在现实里的努力无法支 ...

  9. 30K iOS程序员的简述:如何快速进阶成为高级开发人员

    前言: 本篇文章适用于所有在这个行业已经有了几年时间后想要在职业生涯中取得突破的开发人员,编程人员和程序员(或者你可能刚刚开始,但希望你能看到你的路径) 本文适合那些有着简单愿望的人:你想成为一名高级 ...

随机推荐

  1. LeetCode Count and Say 数数字

    class Solution { public: string countAndSay(int n) { ) "; "; int i,t,count; char c='*'; ;i ...

  2. php使用GD库实现图片水印和缩略图——生成图片缩略图

    今天呢,就来学习一下在php中使用PD库来实现对图片水印的文字水印方法,不需要PS哦! 首先,准备素材 (1)准备一张图片 (2)准备一张水印(最好是透明的,即背景是白色底) (3)准备一中字体(在电 ...

  3. innobackupex备份脚本

    #!/bin/bash # 10 23 * * * /bin/bash /data/script/backup.sh BDATE=`date +%Y%m%d%H%M%S`BPATH=/data/bac ...

  4. 2018.6.10 Oracle数据库常见的错误汇总

    1.ClassNoFoundException 找不到注册驱动 可能原因:1>驱动名称不对 2>没有导入数据库驱动包 2.SQl 语句中可以使用任何有效的函数,函数操作的列,必须指定别名, ...

  5. appium---adb通过wifi连接手机

    前几天接到领导的安排,想要测试下apk的耗电量,可以通过手机adb命令进行监控手机电量的变化:但是这样如果通过USB连接手机的话,USB就会自动给手机进行充电,无法达到我们想要的结果,于是想到了通过w ...

  6. java中利用JOptionPane类弹出消息框的部分例子

    转: http://www.cnblogs.com/wangxiuheng/p/4449917.html http://blog.csdn.net/penjie0418/article/details ...

  7. C# 运用DirectoryInfo类和FileInfo类

    DirectoryInfo类和FileInfo类的基类都是FileSystemInfo类,这个类是一个抽象类,也就是说你不可以实例化该类,只能通过继承产生其子类并实例化其子类.然而你却可以运用由该类定 ...

  8. 笔试算法题(46):简介 - 二叉堆 & 二项树 & 二项堆 & 斐波那契堆

    二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者 ...

  9. graphQL 启动报错No method or field found with any of the following signatures (with or without one of [interface graphql.schema.DataFetchingEnvironment] as the last argument), in priority order:

    -------------------root.graphqls---------------------------这个文件用来定义属性字段,必须和实体类相同 文件里面的字段写错会报这个错误 com ...

  10. 爬虫学习(六)——异常处理URLerrors异常处理

    # 异常处理都在urllib.error中进行处理 import urllib.requestimport urllib.error # 第一种异常:该网址不存在url = "http:// ...