一、什么是跨域?
跨域的安全限制都是对浏览器端来说的,服务器端是不存在跨域安全限制的。浏览器的同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。所谓同源即:协议、域名、端口号都相同,否则就是不同源的。
如果要在js里发起跨域请求,则要进行一些特殊处理了。或者,你可以把请求发到自己的服务端,再通过后台代码发起请求,再将数据返回前端。
二、JSONP
JSONP 是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback
或者开始就定义一个回调方法,参数给服务端,然后服务端返回数据时会将这个callback
参数作为函数名来包裹住JSON(是一种传输格式)数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
jsonp 是 json with padding 的缩写,它不属于 Ajax 请求,但它可以模拟 Ajax 请求。
注意:JSONP只支持GET
请求
JSONP的优点是:
- 它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;
- 兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。
JSONP的缺点是:
- 只支持GET请求而不支持POST等其它类型的HTTP请求;
- 只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
1、将不同源的服务器端请求地址写在 script 标签的 src 属性中。
<script src="www.example.com"></script>
<script src=“https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
2、服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。
const data = 'fn({name: "张三", age: "20"})';
res.send(data);
3、在客户端全局作用域下定义函数 fn。
function fn (data) { }
4、在 fn 函数内部对服务器端返回的数据进行处理。
function fn (data) { console.log(data); }
封装 jsonp 函数 代码:
function jsonp (options) {
// 动态创建script标签
var script = document.createElement('script');
// 拼接字符串的变量
var params = '';
for (var attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
// myJsonp0124741
var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
// 它已经不是一个全局函数了
// 我们要想办法将它变成全局函数
window[fnName] = options.success;
// 为script标签添加src属性
script.src = options.url + '?callback=' + fnName + params;
// 将script标签追加到页面中
document.body.appendChild(script);
// 为script标签添加onload事件
script.onload = function () {
document.body.removeChild(script);
}
}
服务器端代码优化之 res.jsonp 方法 :
app.get('/better', (req, res) => {
// 接收客户端传递过来的函数的名称
//const fnName = req.query.callback;
// 将函数名称对应的函数调用代码返回给客户端
//const data = JSON.stringify({name: "张三"});
//const result = fnName + '('+ data +')';
// setTimeout(() => {
// res.send(result);
// }, 1000)
res.jsonp({name: 'lisi', age: 20});
});
发送jsonp请求的示例代码:
jsonp({
url: 'https://wis.qq.com/weather/common',
data: {
source: 'pc',
weather_type: 'forecast_1h',
// weather_type: 'forecast_1h|forecast_24h',
province: '黑龙江省',
city: '哈尔滨市'
},
success: function (data) {
var html = template('tpl', {info: data.data.forecast_1h});
box.innerHTML = html;
}
})