最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 遇到跨域不着急,三种方法帮助你~

    正文概述 掘金(果冻与布丁)   2021-02-24   543

    前言

    • 不管是 ajax 请求、canvas 的渲染等,都有可能牵涉一个问题 - 跨域
    • 跨域是因为受到了浏览器同源策略的影响
    • 我们也经常遇到跨域的问题,这让我们很多功能的实现上都产生了一定影响,我们下面就来看看,如何解决跨域的问题
    • 完整相册 Demo - 相册

    前后端交互问题 - 跨域

    浏览器同源策略

    • 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源
    • 同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收
    • 源 :协议、域名和端口号

    不受同源策略影响的资源引入

    • <script></script><img/><link></link><iframe></iframe> - src

    方案

    • jsonp
    • CORS解决跨域
    • proxy - 服务器代理请求

    jsonp

    • jsonp - JSON width Padding
    • jsonp 的原理 - 通过 <script></script> 不受同源策略影响的特性实现跨域

    简单使用

    • 后端 node - koa
    router.get('/getAjax', ctx => {
        // 直接返还浏览器可执行的 js 代码
        ctx.body = 'var a = 123';
    });
    
    • 前端
    <script src="http://127.0.0.1:1000/getAjax"></script>
    <script>
        console.log(a); // 123
    </script>
    
    • 这么做有一些新的问题产生
      • 变量名污染
      • 交互是为了通信,我把数据传给你,你把数据传回给我,这么做就只是 js 引入,没有任何意义

    动态创建 script 实现请求

    • 我们根据之前的 简单使用 出现的问题,对 jsonp 的 script 进行修改
    1. 使用 paramsquery 进行 客户端->浏览器 的数据传输
    2. 根据需求动态创建 script
    3. 异步问题 - 请求需要时间,那么后面会有可能使得所需数据没加载进来但你却使用了导致报错
    const btn = document.querySelector('button');
    btn.onclick = () => {
        const jsonp = document.createElement('script');
        jsonp.src = `http://127.0.0.1:3000/getAjax`;
        document.head.appendChild(jsonp);
        // 避免异步问题,等 onload 之后再执行
        jsonp.onload = () => {
            console.log(a);
        }
    }
    
    1. onload 这种方式感觉没什么问题,但看着挺蠢的,所以我们可以利用回调再改一下,把回调的方法名传到后台,再由后端返回执行js
    • 后端 node - koa
    router.get('/getAjax', ctx => {
        const { cb, name } = ctx.query;
        ctx.body = `${cb}({
            name: '${name}',
            age: 20
        })`;
    });
    
    • 前端
    const btn = document.querySelector('button');
    btn.onclick = () => {
        const jsonp = document.createElement('script');
        jsonp.src = `http://127.0.0.1:3000/getAjax?name=张三&cb=cbFn`;
        document.head.appendChild(jsonp);
    }
    
    function cbFn(options) {
        console.log(options);
    }
    

    典型例子 - 百度搜索

    • 百度接口
    https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=hello&cb=succFn
    
    • wd - 搜索关键字
    • cb - 回调

    jsonp存在的问题

    • 只能是 get 请求
    • 安全性问题

    CORS跨域设置

    • CORS(Cross-origin resource sharing),跨域资源共享,是一份浏览器技术的规范,用来避开浏览器的同源策略
    • 该设置需要后端配合
    • 实际上就是后端返回数据时携带一个特殊的头信息

    Access-Control-Allow-Origin

    • 当我们的浏览器通过 ajax 发送了一个请求的时候,如果该请求不同源,那么浏览器会去看一下请求头信息里面是否存在一个 Access-Control-Allow-Origin 字段,且当前的域是否在该字段的值内,
    • 如果为真,则表示该数据是可信任的,就接收响应数据
    • 否则拒绝接收
    • 后端 - node - koa
    ctx.set('Access-Control-Allow-Origin', 'http://127.0.0.1:8080'); // 表示只有 http://127.0.0.1:8080 可以访问
    ctx.set('Access-Control-Allow-Origin', '*'); // * 为通配符,表示任何域名都可以访问
    

    CORS 头信息设置

    • CORS请求时,XMLHttpRequest 对象的 getResponseHeader() 只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma
    • 如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定
    • 我们还需要通过两个特殊头信息设置
      1. Access-Control-Allow-Headers - 允许requset设置的头部
      2. Access-Control-Expose-Headers - 允许客户端获取的头部key
    • 后端 - node - koa
    ctx.set({
        'Access-Control-Allow-Origin': 'http://127.0.0.1:8080',
        'Access-Control-Allow-Headers': 'Authorization',
        'Access-Control-Expose-Headers': 'Authorization'
    });
    

    预检请求

    • 在跨站点请求的时候,即使服务器设置了 Access-Control-Allow-Origin ,如非简单请求,也会请求失败,其原因是因为在正式请求前,会有一个预检请求

    • 需预检的请求要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求

    • 预检请求的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响

    • 简单请求 - 满足条件:

      • method

        1. GET
        2. POST
        3. HEAD
      • 除了被用户代理自动设置的头信息(例如 ConnectionUser-Agent和在 Fetch 规范中定义为 禁用首部名称 的其他头信息,允许人为设置的字段为 Fetch 规范定义的 对 CORS 安全的首部字段集合。该集合为:

        1. Accept
        2. Accept-Language
        3. Content-Language
        4. Content-Type(需要注意额外的限制)
        5. DPR
        6. Downlink
        7. Save-Data
        8. Viewport-Width
        9. Width
      • Content-Type 的值仅限于下列三者之一:

        1. text/plain
        2. multipart/form-data
        3. application/x-www-form-urlencoded
    • 解决方案 - 后端允许预检通过

    • 后端 - node - koa

    if(ctx.method === 'OPTIONS') {
        ctx.set('Access-Control-Request-Method', 'POST');
        return ctx.body = ''
    }
    

    后端代理

    • 后端 即能接电话(响应-提供服务),还能打电话(发送请求)

    • 跨域问题是由浏览器的同源策略这个安全机制引起的,我们就可以通过服务器请求数据,不由浏览器直接请求数据,解决跨域问题

    • 即由同源服务器作为代理,访问其他服务器:浏览器 -> 同源服务器 -> 非同源服务器 -> 同源服务器 -> 浏览器

    • node原生

    let data;
    const options = {
        protocol: 'http:',
        hostname: '127.0.0.1',
        port: 3000,
        path: url.replace(/^\/api/, ''),
        method,
        headers,
    }
    const req = http.request(options, res => {
        res.on('data', chunk => {
            data += chunk.toString();
            console.log(`BODY: ${chunk}`);
        })
        res.on('end', () => {
            res.write(data);
            console.log('完成');
        })
    })
    req.on('error', (e) => {
        console.error(`problem with request: ${e.message}`);
    });
    req.end();
    
    • koa-server-http-proxy
    app.use(proxy('/api', {
        target: 'http://127.0.0.1:3000',
        pathRewrite: {
            '^/api': ''
        }
    }));
    

    代理方式

    遇到跨域不着急,三种方法帮助你~ 遇到跨域不着急,三种方法帮助你~

    起源地下载网 » 遇到跨域不着急,三种方法帮助你~

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元