阅读 250

前端解决跨域问题(前端解决跨域问题面试题)

1 跨域产生的原因

  • 跨域浏览器同源策略限制的一类请求场景

  • 什么是同源策略?
    同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

同源策略限制以下几种行为:

1.) Cookie、LocalStorage 和 IndexDB 无法读取 2.) DOM 和 Js对象无法获得 3.) AJAX 请求不能发送 复制代码

2 跨域解决方案

1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域

3 jsonp跨域实现

  • JSONP:利用在页面中创建

  • JSONP跨域的基本原理:由于script 标签不受浏览器同源策略的影响,允许跨域引用资源。因此,通过动态创建 script 标签,然后利用 src 属性进行跨域。

  • JSONP的优点:不受同源策略的限制;兼容性好,在老的浏览器中可以运行;请求完毕后可以通过调用 callback 的方式回传结果。

  • JSONP的缺点:只支持 GET 这种HTTP请求;jsonp在调用失败的时候不会返回各种HTTP状态码;安全性:callback传入的参数是在后端进行了一次拼接,这即代表存在注入的可能,如果后端设计不当,是有可能出现安全风险的。

// jsonp的封装 function jsonp(params) {     // 创建script标签并加入到head中     var callbackName = params.jsonp;     var head = document.getElementsByTagName('head')[0];     // 设置传递给后台的回调参数名     params.data['callback'] = callbackName;     var data = formatParams(params.data);     var script = document.createElement('script');     // 发送请求     script.src = params.url + '?' + data;     // 创建jsonp回调函数     window[callbackName] = function (res) {         head.removeChild(script);         clearTimeout(script.timer);         window[callbackName] = null;         params.success && params.success(res);     };     head.appendChild(script);     // 为了得知此次请求是否成功,设置超时处理     if (params.time) {         script.timer = setTimeout(function () {             window[callbackName] = null;             head.removeChild(script);             params.error && params.error({                 message: '超时'             });         }, 500);     } } // 格式化参数 function formatParams(data) {     var arr = [];     for (var name in data) {         arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));     };     // 添加一个随机数,防止缓存     arr.push('v=' + random());     return arr.join('&'); }          // 获取随机数 function random() {     return Math.floor(Math.random() * 10000 + 500); } 复制代码

jsonp({     url: url,     jsonp: 'jsonpCallback',     data: dataParams,     success: function (res) {         params.success && params.success();     },     error: function (error) {} }) 复制代码

4 为什么要用img标签来进行跨域?

凡带src属性的,必能跨域,所以你可以看到还有种方案叫JSONP。但是src对这个事应该也挺无奈的,算是个历史遗留问题吧,不属于跨域问题的原始设计,就像修了堵墙还挖了个洞出来一样。

5 ping图片跨域

图片Ping是客户端向服务器的单向通信,因为src请求资源不属于同源策略,所以一般可以用来做埋点,比如监听网页的PV(Page View),UV(Unique Visitor)。通俗点讲就是曝光率。

6 canvas跨域图片转base64

/**  * 在线图片转换base64  * @param imgUrl 图片的url  *  *    * */  export function dealImage(imgUrl) {   // 一定要设置为let,不然图片不显示   let image = new Image();   // 解决跨域问题 必须后端设置支持跨域,后端不配合白搭   image.setAttribute('crossOrigin', 'anonymous');   const imageUrl = imgUrl;   // 加随机数,防止图片请求到缓存   image.src = imageUrl + '?v=' + Math.random()   // image.onload为异步加载   image.onload = () => {     var canvas = document.createElement('canvas');     canvas.width = image.width;     canvas.height = image.height;     var context = canvas.getContext('2d');     context.drawImage(image, 0, 0, image.width, image.height);     var quality = 0.8;     // 这里的dataurl就是base64类型       // 使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png,因为压缩成png后base64的字符串可能比不转换前的长!     const dataurl = canvas.toDataURL('image/jpeg', quality);     console.log('wbk dataurl :>> ', dataurl );   } } 复制代码

跨域时,如果资源服务器不允许的话,前端是不能获取到该资源的,也是为了安全考虑,可以尝试做一层代理,但有些服务器也会做防爬处理。

canvas 中的图片可能来自一些第三方网站。在资源服务器不允许的情况下,使用跨域的图片绘制时会污染画布,这是出于安全考虑。在“被污染”的画布中调用 toBlob() toDataURL() getImageData() 会抛出安全警告。

7 尝试使用img标签进行jsonp跨域请求获取在线图片操作(失败)

猜想原因,jsonp只支持get请求跨域,没法操作图片

猜想原因2,jsonp 需要后端进行配合

// jsonp的封装 function jsonp(params) {   // 创建script标签并加入到head中   var callbackName = params.jsonp;   var head = document.getElementsByTagName('head')[0];   // 设置传递给后台的回调参数名   params.data['callback'] = callbackName;   var data = formatParams(params.data);   var img = document.createElement('img');   // 发送请求   img.src = params.url + '?' + data;   // 创建jsonp回调函数   window[callbackName] = function (res) {       head.removeChild(img);       clearTimeout(img.timer);       window[callbackName] = null;       params.success && params.success(res);   };   head.appendChild(img);   // 为了得知此次请求是否成功,设置超时处理   if (params.time) {       img.timer = setTimeout(function () {           window[callbackName] = null;           head.removeChild(img);           params.error && params.error({               message: '超时'           });       }, 500);   } } // 格式化参数 function formatParams(data) {   var arr = [];   for (var name in data) {       arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));   };   // 添加一个随机数,防止缓存   arr.push('v=' + random());   return arr.join('&'); }        // 获取随机数 function random() {   return Math.floor(Math.random() * 10000 + 500); }


作者:怕是个胖虎哟
链接:https://juejin.cn/post/7034054193941856292

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐