跨域

头像
WinRT
    阅读 4 分钟

    跨域的相关概念

    什么是跨域?

    域名的组成:
    image.png

    同源策略是由 Netscape 提出的著名安全策略,是浏览器最核心、基本的安全功能,它限制了一个源(origin)中加载文本或者脚本与来自其他源(origin)中资源的交互方式,所谓的同源就是指协议、域名、端口相同。

    当浏览器执行一个脚本时会检查是否同源,只有同源的脚本才会执行,如果不同源即为跨域

    为什么会出现跨域?

    浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用(通常指使用 XMLHttpRequest 请求)。

    浏览器的同源策略

    同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制(防止恶行请求)。
    比如,假设有一个黑客叫做小黑,他从网上抓取了一堆美女图做了一个网站,每日访问量爆表。

    为了维护网站运行,小黑挂了一张收款码,觉得网站不错的可以适当资助一点,可是无奈伸手党太多,小黑的网站入不敷出。

    于是他非常生气的在网页中写了一段js代码,使用ajax向淘宝发起登陆请求,因为很多数人都访问过淘宝,所以电脑中存有淘宝的cookie,不需要输入账号密码直接就自动登录了,然后小黑在ajax回调函数中解析了淘宝返回的数据,得到了很多人的隐私信息,转手一卖,小黑的网站终于盈利了。

    如果跨域也可以发送AJAX请求的话,小黑就真的获取到了用户的隐私并成功获利了!!!

    平时在使用良性的请求

    百度统计

    有哪些限制?

    • Cookie、LocalStorage 和 IndexDB 无法读取
    • DOM无法获取
    • Ajax(Asynchronous JavaScript and XML)请求不能发送

    Ajax请求步骤

        // 1、创建XMLHttpRequest对象
        var xmlhttp=new XMLHttpRequest();
        // 2、使用open方法设置请求的参数。open(method,url,是否异步)。
        xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);
        // 3、发送请求
        xmlhttp.send();
        // 4、注册事件。 注册onreadystatechange事件,状态改变时就会调用。
        xmlhttp.onreadystatechange=function()
        {    // 5、获取返回的数据,更新UI。
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
            }
        }

    解决跨域请求的技术

    JSONP(全称:JSON with Padding)

    概念:原理就是利用了 script 标签不受浏览器同源策略的限制,在页面中动态插入了 script,script 标签的 src 属性就是后端 api 接口的地址,并且以 get 的方式将前端回调处理函数名称告诉后端,后端在响应请求时会将回调返还,并且将数据以参数的形式传递回去。

    扩展:<script> 、<img>、 <iframe>、 <link>等带src属性的标签都可以跨域加载资源,而不受同源策略的限制。

    核心代码

    前端

    var script = document.createElement('script');
    script.src = 'http://localhost:21602/api/Login/TestjsonpForVue?callback=_callback';
    
    document.body.appendChild(script);   
    var _callback = function(obj) {
        console.log(obj);
    }

    后端核心代码(采用.netcore api实现):

            [HttpGet]
            public void TestjsonpForVue(string callback)
            {
                TokenModelJwt tokenModelJwt = new TokenModelJwt()
                {
                    Role = "jsonp",
                    Uid = 1,
                    Work = "dsdf"
                };
                var modlestr = JsonConvert.SerializeObject(tokenModelJwt);
                string call = callback + "(" + modlestr + ")";
                Response.WriteAsync(call);
             }
    

    后端返回结果:
    image.png

    劣势

    • 这种方式只能发生get请求
    • 确定jsonp的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定
    • 不太安全,可能也会受到攻击

    优势

    • 很简单
    • 老式浏览器全部支持,服务器改造非常小

    CORS 跨域资源共享(全称:Cross-Origin Resource Sharing)

    概念:CORS是一种允许当前域(origin)的资源被其他域(origin)的脚本请求访问的机制。当使用 XMLHttpRequest 发送请求时,浏览器如果发现违反了浏览器同源策略就会自动加上一个请求头 origin,后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin,值就是发起请求的源地址,浏览器得到响应会进行判断 Access-Control-Allow-Origin 的值是否和当前的地址相同,只有匹配成功后才进行响应处理。

    核心代码

    前端代码:

        // 1、创建XMLHttpRequest对象
        var xmlhttp=new XMLHttpRequest();
        // 2、使用open方法设置请求的参数。open(method,url,是否异步)。请求资源地址要用绝对路径。
        xmlhttp.open("post","http://localhost:21602/api/login/TestCORSForVue",true);
        // 3、发送请求
        xmlhttp.send();
        // 4、注册事件。 注册onreadystatechange事件,状态改变时就会调用。
        xmlhttp.onreadystatechange = function()
        {    // 5、获取返回的数据,更新UI。
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {           
                console.log(xmlhttp.responseText);
            }
        }

    后端代码(采用.netcore api实现)

    • 注入服务:
      public void ConfigureServices(IServiceCollection services)
      {          
                services.AddCors(c =>
                {
                    //一般采用这种方法
                    c.AddPolicy("LimitRequests", policy =>
                    {         
                        policy
                        //  Adds the specified origins to the policy.
                        // 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的
                        // 注意,http://127.0.0.1:5401 和 http://localhost:5401 是不一样的,尽量写两个
                        .WithOrigins("https://fiddle.jshell.net") 
                        .AllowAnyHeader()//Ensures that the policy allows any header.
                        .AllowAnyMethod();
                    });
                });
      }
    • http请求管道中开启中间件:

           public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                app.UseCors("LimitRequests");//将 CORS 中间件添加到 web 应用程序管线中, 以允许跨域请求。
            }

    编写api

      [Route("api/[controller]/[action]")]
      [ApiController]
      public class LoginController : ControllerBase
      {
          [HttpPost]
          public ActionResult TestCORSForVue()
          {
               return Ok("TestCORS");
          }
       }

    请求结果:
    image.png

    优势

    • 支持所有 Http 谓词请求
    • 不用注意接口规则
    • 可用在生产环境

    劣势

    • 部分老的浏览器不支持

    引用/参考:https://www.bilibili.com/vide...


    WinRT
    21 声望4 粉丝

    临渊羡鱼,不如退而结网


    引用和评论

    0 条评论