解决跨域之—— JSONP

3,454 阅读2分钟

跨域

跨域,被称为面试官100%、10000%会问的问题

解决跨域的方法有很多,这里详细讲下JSONP,其他方法后续可能也会写文章, 首先 JSONPJSON 没有任何关系,就像 Java 与 JavaScript,林允与林允儿

希望大家看完这篇文章,能了解的知识:

  1. 出现跨域的原因
  2. 什么时候会出现跨域
  3. JSONP是如何解决跨域的,有什么缺点

出现跨域的原因:浏览器的同源策略

要了解浏览器的同源策略,我们必须知道一段URL地址的组成

例如: https:// www.baidu.com :8080 /userInfo

其中 https是协议号 —— www.baidu.com 是域名—— :8080是端口 ——/userInfo是路径

当协议号和域名和端口都相同时,才符合同源策略

跨域通常发生在什么时候

是在前端发送请求的时候发生跨域,还是在后端接收到请求,响应请求的时候发生跨域?

我们写段简单代码测试一下

前端代码

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
html
    <button id="btn">获取数据</button>
js
        let btn = document.querySelector("#btn");
        btn.addEventListener("click", function(){
            $.ajax({
                url:'http://localhost:3000',
                data:{name:'yangjun'},
                method:'GET',
                success(res){
                    console.log(res);
                }
            })
        },false)

后端代码

const Koa = require('koa')
const app = new Koa()

const main = (ctx,next)=>{
    console.log(ctx.query);
    ctx.body = 'hello world'
}

app.use(main)
app.listen(3000,()=>{
    console.log('项目已启动');
})

当前端发送请求时,因为不符合浏览器的同源策略,会触发跨域

前端显示

后端显示

可以看出来,后端收到了前端发送的请求,但是前端并没有收到后端的响应。

说明跨域发生在后端响应回来的数据,在前端接收的时候被浏览器的跨域机制拦截了下来

解决跨域的方法之——JSONP

1. JSONP思想

JSONP 是一种思想,并不是一个方法, 有些请求是不会受到浏览器的同源策略的影响的。

例如:src、href

  1. <script src=""></script>
  2. <img src="">
  3. <link rel="stylesheet" href="">

JSONP就是利用script 的 src属性加载资源时不受同源策略的影响的这一特性,并且script会将引用的外部文件的文本内容当做js代码来进行解析

2. JSONP实现

前端代码

html
    <button id="btn">获取数据</button>
js
        const jsonp = (url, params, cb) => {
            return new Promise((resolve, reject) => {
                const script = document.createElement('script');
                params = { ...params, cb: cb }
                const arr = Object.keys(params).map(key => `${key}=${params[key]}`)
                script.src = `${url}?${arr.join('&')}`
                document.body.appendChild(script)
                //后端会返回一个字符串给前端,  cb('我今年18岁')
                
                //全局声明一个方法,方法名为cb
                window[cb] = (data) => {
                    resolve(data)
                }
            })
        }
        let btn = document.getElementById('btn')
        btn.addEventListener('click', () => {
            jsonp('http://localhost:3000', { name: '蜗牛', age: 18 }, 'callback').then(res => {
                console.log(res)
            })
        })

后端代码

const Koa = require('koa')
const app = new Koa()

const main = (ctx,next)=>{
    //console.log(ctx.query); { name: '我', age: '18', cb: 'callback' }
    const {name,age,cb} = ctx.query
    const userInfo = `${name}今年${age}岁`
    const str = `${cb}(${JSON.stringify(userInfo)})` // 'callback(userInfo)'
    //console.log(str); callback("我今年18岁")
    ctx.body = str
}

app.use(main)
app.listen(3000,()=>{
    console.log('项目已启动');
})

前端显示

image.png

后端显示

image.png

3. JSONP实现原理

前端在window声明一个方法,此时并没有调用

            window[cb] = (data) => {
                resolve(data)
            }
  1. 因为script请求的数据,浏览器引擎会直接执行,好比请求的 jquery,引擎会执行这段代码
  2. 因为script请求的数据,我们没有办法直接操作,或者说请求到的数据我们实际上看不见,但是存在

所以在后端以函数形式返回给前端时,并且前端已经声明过这个函数,函数会直接调用,此时data为后端返回数据

4.JSONP缺点: 只支持get类型请求

在考虑到安全性的时候,不适用,因为get请求携带的参数会在url地址显示

结束了!!!