jsonp解决跨域,不是很简单吗,这有啥可说的……原理我都知道,巴拉巴拉……
哎呀,今天遇到了一个业务中需要解决跨域的问题,后端同学不愿意处理,只能自己来做。
跨域和jsonp
浏览器同源策略,为防止被恶意攻击,不允许不同协议、不同域名、不同端口(任一不一致)进行跨域访问。
跨域的解决方法有很多:CORS、nginx代理、websocket、postMessage等等,包括jsonp。
jsonp解决跨域问题的原理是:动态script标签,浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行,没有阻塞情况。
优点:
简单,兼容性好
缺点:
无法发送post请求,仅支持get请求,并且不太安全,可能遭到XSS攻击。还有一点,无法知道请求是否失败,大多是通过超时来判断。
背景
需求背景是产品想要把涉及到当前项目的所有后端服务以及前端项目的版本号都显示显示在前端页面中,方便交付同学查看版本号。
而前端项目有三个,直接调其他前端项目的服务存在跨域问题。
灵光一闪,jsonp呀,说整就整。
const callbackFn = function(data) {
console.log(data);
}
const url = "http://fe.baidu.test.com/.version.json?callback=callbackFn"
const oScript = document.createElement('script')
oScript.type = 'text/javascript'
oScript.src = url
document.body.appendChild(oScript)
发现浏览器报了警告:资源的MIME类型有问题
使用jsonp时,response 头不应该设置 content-type 为 application/json,而应该设置为 application/javascript,否则在开启了 x-content-type-options:nosniff 头后会导致浏览器不执行 JSONP 回调。
jsonp走不下去了,只能换一种思路,ajax呗,需求算是完成了。
$ajax(options) {
options = Object.assign({
url: '',
method: 'get',
data: null,
headers: {}
}, options)
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest;
xhr.open(options.method, options.url)
// 自定义请求头
Object.keys(options.headers).forEach(key => {
xhr.setRequestHeader(key, options.headers[key])
})
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (/^(2|3)\d{2}$/.test(xhr.status)) {
resolve(JSON.parse(xhr.responseText))
return;
}
reject(xhr)
}
}
xhr.send(options.data)
})
}
当然,用jQuery的可以直接用$getJSON方法,这个方法是封装ajax设置content-Type:application/json来实现的。源码如下:
getJSON: function( url, data, callback ) {
return jQuery.get( url, data, callback, "json" );
},
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
// shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}
return jQuery.ajax({
type: method,
url: url,
data: data,
success: callback,
dataType: type
});
};
}
没了~