什么是跨域
简单来说就是 A 网站的 javascript 代码试图访问 B 网站,包括提交和获取内容。由于安全原因,跨域访问是被各大浏览器所默认禁止的。
协议、ip(域名)、端口号 三者之中只要有一个不一样就是跨域
比如在http://www.xxx.com:80中调用下面三个都是跨域
http://mail.xxx.com:80 跨域(域名不同)
https://www.xxx.com:80 跨域(协议不同)
http://www.xxx.com:8080 跨域(端口不同)
如何解决跨域
jsonp
核心原理: 利用了 href 和 src 属性能够跨域请求数据的特性。
但是要注意JSONP只支持GET请求,不支持POST请求。
比如在我们学习JQuery时,要使用JQuery需要先引入JQuery文件,我们当时就是使用< script>标签来引入的,这就是使用jsonp来实现跨域请求的一个案例
script标签需要请求服务器的一个地址,该地址能够返回一个函数调用的字符串,该字符串会在html页面中被当成函数调用来执行,函数字符串中的内容就是服务器端给浏览器端返回的数据
案例
例子:使用express来搭建一个服务器,并启动服务
const app = require('express')()
app.listen(3000, ()=>{
console.log('running....');
})
app.get('/jsonp',(req,res)=>{
// abc()函数字符串中的内容就是服务器返回给客户端的数据
res.send('abc()')
})
app.get('/bbb',(req,res)=>{
console.log(req.query);
res.send('abc({type:'text',age:12})')
})
再创建一个html文件,在页面上没有特殊指定,默认使用get请求
<script src="http://localhost:3000/jsonp"></script>
我们可以看到,请求成功了,也返回了数据,但是报错了
这是因为请求返回的数据会被当成js代码直接执行,而我们没有声明abc,因此会报错。但是如果我们在html页面中定义了abc的话
<script>
function abc(){
console.log('返回值直接执行');
}
</script>
<script src="http://localhost:3000/jsonp"></script>
我们可以看到,我们只是定义了abc方法并没有执行它,但是该函数执行了,这是因为我们发送请求后,返回了abc(),这被当作js代码直接执行了
也可以利用它发送数据
<script>
function abc(data){
console.log(data);
}
</script>
<script src="http://localhost:3000/bbb?type=12&age=11"></script>
服务器能接收到传递的数据,页面也能接受到服务器返回的数据
jsonp核心就是当我们请求一个服务器地址时,服务器需要返回给我们一个函数执行的模块,函数中的参数就是服务器返回给我们的数据
点击事件发送jsonp请求
<body>
<button id="btn">发送jsonp</button>
<script>
// 定义返回函数
function abc(data){
console.log(data);
}
document.querySelector('#btn').onclick = ()=>{
// 创建script标签
var script = document.createElement('script')
// 为script标签添加srcshuxing并设置请求地址
script.src = 'http://localhost:3000/bbb?type=12&age=11'
// 将script标签添加到html页面中
document.body.appendChild(script)
}
</script>
函数的封装
如果想要调用其他服务器,只需要改变src即可,因此我们可以将它封装起来
初步封装
function abc(data){
console.log(data);
}
document.querySelector('#btn').onclick = ()=>{
jsonp('http://localhost:3000/bbb?type=12&age=11')
}
//参数为请求的url地址
function jsonp(url){
// 创建script标签
var script = document.createElement('script')
// 为script标签添加srcshuxing并设置请求地址
script.src = url
// 将script标签添加到html页面中
document.body.appendChild(script)
}
完整封装: 将abc方法也放到封装函数中
我们在script中声明的函数和变量都是挂载到windows对象上的
document.querySelector('#btn').onclick = ()=>{
jsonp('http://localhost:3000/bbb?type=12&age=11')
}
//参数为请求的url地址
function jsonp(url){
// 创建script标签
var script = document.createElement('script')
// 为script标签添加srcshuxing并设置请求地址
script.src = url
// 将script标签添加到html页面中
document.body.appendChild(script)
window.abc=(data)=>{
console.log(data);
}
}
最终封装 将数据传递也封装进去
// 参数1: 请求的服务器端的url地址
// 参数2: 发送给服务器端的数据
function jsonp (url, data) {
// 1. 创建script标签
var script = document.createElement('script')
// 2. 为script标签增加src属性,设置请求地址
// 判断data的数据类型,如果是对象则调用getparmas函数,如果不是则不需要调用
if (typeof data === 'object') {
data = getParams(data)
}
script.src = url + '?' + data
// 3. 将script标签添加到html页面中
document.body.appendChild(script)
// 4. 将abc函数放在函数体内
window.abc = function (data) {
console.log(data)
}
}
function getParams (obj) {
var str = ''
for (var k in obj) {
str += k + '=' + obj[k] + '&'
}
str = str.slice(0, str.length - 1)
return str
}