最近遇到一个需求,需要做一个网页实现停电查询的功能。
不知道是跨域问题
我建站使用的是快站,但是请求数据的来源来自于国家电网。快站(https://www.kuaizhan.com/)使用的协议是使用 ssl 加密的 https 国家电网(http://www.95598.cn/)使用的是http 二者协议不同没有办法通信,使用 ajax 时会报错。
于是我改为自己写一个网站,然后网站采用http协议。在使用国家电网查询信息的时候,打开控制台,分析报文,发现95598(电网)使用json来传输数据,这为我的需求解决提供了可能性,我也可以使用ajax发送get/post请求报文来获取json数据。
定位问题为跨域
在网页中使用$.ajax 获取数据代码如下
$.ajax({
type:"get",
url:"http://www.95598.cn/95598/outageNotice/queryOutageNoticeList?orgNo=51412&outageStartTime=2017-08-16&outageEndTime=2017-08-23&scope=&provinceNo=51101&typeCode=&lineName=&anHui=02",
async:true,
success:function(data){
if(data.query.results) {
//$("#outage").text(JSON.stringify(data.query.results));
var J_data = JSON.parse(JSON.stringify(data.query.results));
//alert(J_data.json.today);
messageStr(J_data.json);
} else {
$("#content").text('no such code: ' + code);
}
}
});
然后报错,错误如下
[Web浏览器] "XMLHttpRequest cannot load http://www.95598.cn/95598/outageNotice/queryOutageNoticeList?orgNo=51412. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8020' is therefore not allowed access." /MyProject/index.html (0)
错误的意思是不可以请求非同源的数据,除非请求源的头部添加了,Access-Control-Allow-Origin:* 这样其他对象可以来请求数据。
后台不在我这里,我没有办法在网站中添加 Access-Control-Allow-Origin,所以这时候要采用其他办法
解决方式:JSONP
$(document).ready(function(){
var url='http://localhost:8080/WorkGroupManagment/open/getGroupById"
+"?id=1&callback=?';
$.ajax({
url:url,
dataType:'jsonp',
processData: false,
type:'get',
success:function(data){
alert(data.name);
},
error:function(XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.readyState);
alert(textStatus);
}});
});
其与json传输不同的地方有两点:
1.在请求中要 dataType:'json' ==> dataType:'jsonp'
2.在返回的数据方面 json :
{
"message":"获取成功",
"state":"1",
"result":{"name":"工作组1","id":1,"description":"11"}
}
jsonp:
callback({
"message":"获取成功",
"state":"1",
"result":{"name":"工作组1","id":1,"description":"11"}
})
jsonp比json多了一个回调函数的函数名,因为二者工作方式不同,AJAX其实是XMLHttpRequest 请求来实现异步加载数据,而jsonp原理相当于加载一段js代码在获取数据的同时返回了js对象,这样就可以直接使用callback。但是这样方式并不适合我使用,所以继续去找下一种解决办法
解决方式:XHR2
HTML5中提供的XMLHTTPREQUEST Level2(及XHR2)已经实现了跨域访问。但ie10以下不支持
只需要在服务端填上响应头:
header("Access-Control-Allow-Origin:*");
/*星号表示所有的域都可以接受,*/
header("Access-Control-Allow-Methods:GET,POST");
这种我没有试过,因为我并没有服务端。而且这种方案也不能帮助我解决需求
解决方式:YQL
雅虎的Yahoo Query Language (YQL)通过它可以把 Web 上的各种数据服务作为数据库表来查询,并获得结果。
通过yql服务, 可以把https://openapi.baidu.com/api的内容再次封装, 还可以把接口返回的内容, 再次使用sql语句查询, 然后再通过yql服务返回最终结果
- 具体使用方法:
- 打开网址https://developer.yahoo.com/yql/
- 找到示例, 把默认的示例替换成你自己的: select * from html where url='你要访问的api地址'
- 然后点击Test, 就能看到Response里面已经有查询结果了
- 还可以定制查询select id,name from html where url='你要访问的api地址', 定制返回结果
- 最后复制Endpoint里面的链接大概是这样https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20urlles.org%2Falltableswithkeys
- 最后, 把得到的链接地址复制到自己的js里面去执行就能正确拿到json