浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
跨域的方式:
JSONP
html中script标签可以引入其他域下的js,比如引入线上的jquery库。利用这个特性,可实现跨域访问接口。需要后端支持。
JSONP看起来和JSON差不多,只不过被包含在函数中调用中的JSON,就像下面这样:
callback({"name":"Jack"});
以请求高德API天气接口为例,本地调用高德API数据接口,通过动态元素来使用,为src属性指定一个跨域URL。
可以不受限制的从其他域加载资源。
var script = document.createElement('script');
script.src = "http://restapi.amap.com/v3/weather/weatherInfo?key=你的key&output=JSON&extensions=base&callback=showWeather&city="+$('#cityname').value;
document.head.appendChild(script);
//document.head.removeChild(script);
//可以在创建script元素后将它删除,避免head里script标签过多,删除标签不影响script获取地址中的资源
//我在url都设定了一个回调函数showWeather;在加载API接口时,返回的数据是这样的:
showWeather({"status":"1","count":"1","info":"OK","infocode":"10000","lives":[{"province":"上海","city":"上海市","adcode":"310000","weather":"晴","temperature":"33","winddirection":"西","windpower":"4","humidity":"59","reporttime":"2017-07-16 19:00:00"}]})
//返回的数据被包裹在showWeather中,因此我们就可以把showWeather当成一个函数,里面的内容即为传入函数的内容,只需要将返回的JSON数据解析成JavaScript对象就可以使用了
但是我在将返回数据解析成JavaScript对象时遇到了报错:
function showWeather(data){
data = JSON.parse(data);
}
Uncaught SyntaxError: Unexpected token o in JSON at position 1
[object Object]
然后我直接打印出data,发现data已经是Object格式的了,并不需要再次解析。
console.log(data);
//{status: "1", count: "1", info: "OK", infocode: "10000", lives: Array(1)}
经查阅资料后发现,Object在作为JSON.parse
的参数时会先转为string,默认toString实现会将Object转为"[object Object]"
,JSON.parse
将第一个字符'['理解为数组开始,第二字符'o'就不知道怎么处理了。
如果不确定可以加入这行代码:
if (typeof data === 'string') {
data = JSON.parse(data);
}
因此只需要直接使用返回的data就可以了,不需要另外再对data进行解析。
另:jQuery中$.ajax()
方法已经对jsonp进行了封装,它会直接在返回的数据上默认加一个函数头,在success:function()
中可以直接使用,不需要进行另外的函数设置。
HTML页面代码:
Title
请输入需要查询的城市
今天天气
城市:
天气:
温度:
风向:
风力:
湿度:
postMessage
由于同源策略的限制,JavaScript 跨域的问题,一直是一个颇为棘手的问题。HTML5 提供了在网页文档之间互相接收与发送信息的功能。使用这个功能,只要获取到网页所在窗口对象的实例,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。
要想接收从其他窗口发送来的信息,必须对窗口对象的 onmessage 事件进行监听,其它窗口可以通过 postMessage 方法来传递数据。
语法:
otherWindow.postMessage(message, targetOrigin);
otherWindow
其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
该方法使用两个参数:第一个参数为所发送的消息文本,但也可以是任何 JavaScript 对象(通过 JSON 转换对象为文本),第二个参数为接收消息的对象窗口的 URL 地址,可以在 URL 地址字符串中使用通配符'*'指定全部地。
为了模拟本地跨域,我在hosts里添加了两个不同的域名:
127.0.0.1 a.com
127.0.0.1 b.com
127.0.0.1 c.com
在父页面里嵌入了一个子页面,调用postMessage方法向子页面发送数据。在子窗口监听onmessage事件,并显示到input框内。
父页面代码:
PostMessage A
实现PostMessage实现跨域
子页面代码:
PostMessage B
在进行跨域的时候,设置好hosts后,启用本地服务器后,打开a.com时需要加上端口号!!
即在地址栏输入:a.com:8080/a.html
因为访问网页时都是要通过IP地址及端口号进行访问的,平时我们经常打开的网页绝大多数是超文本传输协议,即http,不要求用户输入网页“http://”的部分。同样,“80”是超文本传输协议文件的常用端口号,因此一般也不必写明。一般来说用户只要键入统一资源定位符的一部分,比如"www.baidu.com",此处的端口号是默认的80端口。
而我在本地启用的服务器需要访问8080端口,因此需要手动输入,如果不输入就无法正常访问。