首页 > 其他分享 >前端解决跨域问题的方法:jsonp

前端解决跨域问题的方法:jsonp

时间:2022-08-24 20:11:17浏览次数:107  
标签:请求 script url 前端 let showBox jsonp 跨域

同源策略

同源策略/SOP(Same origin policy)是一种约定,是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策略,浏览器很容易受到 XSS、 CSFR 等攻击。

同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。源就是协议、域名和端口号。

1.非同源的限制

当一个页面中使用XMLHTTPRequest(XHR请求)对象发送HTTP请求时,必须保证当前页面和请求的对象是同源的,即协议、域名和端口号要完全一致,否则浏览器就会阻止此跨域请求返回的数据。

2.什么是跨域?

由于浏览器为了防止CSRF攻击(Cross-site request forgery跨站请求伪造),避免恶意攻击而带来的风险而采取的同源策略限制。

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

如何解决跨域

1.后端解决

response.setHeade('Access-Control-Allow-Origin','*')  //设置所有的请求地址都允许跨域

response.setHeade('Access-Control-Allow-Origin-Method','*')  //设置所有的请求方法都允许跨域

2.前端解决

  • jsonp(常用)
  • 代理服务器(常用)
  • websocket(套接字,走的是tcp-ip协议)
  • 通过 iframe script link 标签请求资源(src、href)

jsonp 实现跨域请求

浏览器对script标签src属性、link标签ref属性和img标签src属性等没有这这种限制,利用这个“漏洞”就可以很好的解决跨域请求。JSONP就是利用了script标签无同源限制的特点来实现的,当向第三方站点请求时,我们可以将此请求放在<script>标签的src属性里,这就如同我们请求一个普通的JS脚本,可以自由的向不同的站点请求

通过在请求的 url 后指定一个回调函数,然后服务器在返回数据的时候,会构建一个 json 数据的包装,这个包装就是回调函数,然后返回给前端,前端接收到数据后,因为请求的是脚本文件,所以会直接执行,这样我们先前定义好的回调函数就可以被调用,从而实现了跨域请求的处理。这种方式只能用于 get 请求

JSONP的优点:

  • 像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制
  • 它的兼容性更好,在很多老版本的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
  • 并且在请求完毕后可以通过回调函数回传结果;
  • 由于只支持get请求,所以它的速度较快。

JSONP的缺点:

它只支持GET请求而不支持POST等其它类型的HTTP请求; 所以jsonp使用在查询场景居多

实现示例

 

百度搜索接口:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=miqi&cb=fn

 

wd表示关键词,cb表示回调函数。通过回调函数可以将响应的结果拿到

 

 

<script>
    // var wd = '奥特曼'
    function fn(result){
     console.log(result);
    }
</script>
<script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=奥特曼&cb=fn"></script>

 

 

JSONP的封装

普通封装

function jsonp(url,param={},paramName,callback){
    if(typeof url != 'string'){
        throw new Error('url必须为字符串')
    }
    url += '?'
    // 将param转为&拼接
    for(let key in param){
        url += `&${key}=${param[key]}`
    }
    //函数名需要加工(保持的函数名的唯一)
    let callbackName = 'fn' + Date.now() + Math.ceil(Math.random()*10)
    //加给对应的window
    window[callbackName] = callback
    //将参数名和回调函数名传入
    url += `&${paramName}=${callbackName}`
    //创建一个script标签
    let script = document.createElement('script')
    //指定对应的src地址
    script.src = url
    //加给body
    document.body.appendChild(script)
    //script标签加载完毕
    script.onload = function(){
        this.remove() //将script标签删除
        delete window[callbackName] //将对应的属性删除
    }
}

测试代码:

  <body>
    <input type="text" class="input" />
    <ul class="showBox"></ul>
    <script src="./jsonp.js"></script>
    <script>
      let inp = document.querySelector('.input');
      let showBox = document.querySelector('.showBox');

      inp.oninput = function () {
        let wd = this.value;
        if (wd) {
          jsonp(
            'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',
            {
              wd,
            },
            'cb',
            function (res) {
              showBox.innerHTML = '';
              res.s.forEach((v) => {
                showBox.innerHTML += `<li>${v}</li>`;
              });
            }
          );
        } else {
          showBox.innerHTML = '';
        }
      };
    </script>
  </body>

使用promise封装

function jsonp(url,param={},paramName){
    return new Promise((resolve,reject)=>{
        if(typeof url != 'string'){
            throw new Error('url必须为字符串')
        }
        url += '?'
        // 将param转为&拼接
        for(let key in param){
            url += `&${key}=${param[key]}`
        }
        //函数名需要加工(保持的函数名的唯一)
        let callbackName = 'fn' + Date.now() + Math.ceil(Math.random()*10)
        //加给对应的window
        window[callbackName] = resolve //resolve里面的参数会被then接收 这个resolve会被服务器自动调用并传入参数
        //将参数名和回调函数名传入
        url += `&${paramName}=${callbackName}`
        //创建一个script标签
        let script = document.createElement('script')
        //指定对应的src地址
        script.src = url
        //加给body
        document.body.appendChild(script)
        //script标签加载完毕
        script.onload = function(){
            this.remove() //将script标签删除
            delete window[callbackName] //将对应的属性删除
        }
        //script报错的时候
        script.onerror = function(err){
            reject('错误'+err)
        }
    })
}

测试代码:

  <body>
    <input type="text" class="input" />
    <ul class="showBox"></ul>
    <script src="./jsonpPromise.js"></script>
    <script>
      let inp = document.querySelector('.input');
      let showBox = document.querySelector('.showBox');

      inp.oninput = function () {
        let wd = this.value;
        if (wd) {
          jsonp(
            'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',
            {
              wd,
            },
            'cb'
          ).then((res) => {
            showBox.innerHTML = '';
            res.s.forEach((v) => {
              showBox.innerHTML += `<li>${v}</li>`;
            });
          });
        } else {
          showBox.innerHTML = '';
        }
      };
    </script>
  </body>

 

标签:请求,script,url,前端,let,showBox,jsonp,跨域
From: https://www.cnblogs.com/qianduanLamp/p/16616977.html

相关文章

  • 前端开发3
    目录一、CSS盒子模型1.margin外边距2.padding内填充二、浮动布局(float)1.浮动的特点2.浮动的三种取值3.clear属性4.清除浮动4.1.清除浮动主要的三种方式:4.2.伪元素清除法(使......
  • #前端算法救赎系列#LeetCode01.两数之和
    1.两数之和给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。示例1:输入:nums=[2,7,11,1......
  • has been blocked by CORS policy跨域问题解决
    title:hasbeenblockedbyCORSpolicy跨域问题解决我们在前端调用接口时,浏览器有时候会报错:XXXXformXXXXXhasbeenblockedbyCORSpolicy:No'Access-Control-......
  • 前端架构-分层而治,铁打的MV流水的C
    大家好,我是Eluxjs的作者,Eluxjs是一套基于“微模块”和“模型驱动”的跨平台、跨框架『同构方案』,欢迎了解...文前声明,以下推断和结论纯属个人探索,鉴于本人知识水平所限,谬......
  • 前端Day05
    好久没更新厌恶怠惰的自己 精灵图sprites:使用background属性进行设置 字体图标: CSS三角:(设置边框颜色为transparent再对三角部分独立设置颜色) CSS界面样式......
  • django中发送post请求,报错csrf跨域问题,解决的办法?
    方法一:在setting.py文件中找到MIDDLEWARE字段,然后注释掉带有csrf的那一行。方法二:在发送请求的html文件的form表单中添加一行{%csrf_token%},即可解决。......
  • 前端02
    目录表单标签css操作CSS简介选择器基本选择器组合选择器属性选择器分组与嵌套伪类选择器伪元素选择器操作优先级字体相关操作背景相关操作边框相关操作隐藏属性-display表......
  • 【全网最全】2022最新版前端 -- 面试题
    @目录一、HTML1、语义话的目的是什么?2、HTML5新增元素3、cookie与sessionStorage和localStorage的区别二、CSS1、CSS有哪些基本的选择器,执行先后顺序?2、垂直水平居中方式有......
  • 前端学习-2
    目录表单知识CSS层叠样式表CSS基本选择器CSS组合选择器CSS属性选择器CSS选择器之分组与嵌套CSS选择器之伪类选择器CSS选择器之伪元素选择器CSS选择器优先级字体样式背景属......
  • 前端CSS
    今日内容form表单标签知识补充1.获取用户输入的标签两大重要属性 name属性 类似于字典的键 value属性 类似于字典的值form表单朝后端发送数据的时候必须要有name......