代码改变世界

6、什么是跨域?跨域解决方案?

2021-08-03 20:30  石吴玉  阅读(206)  评论(0编辑  收藏  举报

参考:https://blog.csdn.net/qq_38128179/article/details/84956552

一、为什么会出现跨域问题

出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。

 

二、什么是跨域

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

当前页面url 被请求页面url 是否跨域 原因
http://www.test.com/ http://www.test.com/index.html 同源(协议、域名、端口号相同)
http://www.test.com/ https://www.test.com/index.html 跨域 协议不同(http/https)
http://www.test.com/ http://www.baidu.com/ 跨域 主域名不同(test/baidu)
http://www.test.com/ http://blog.test.com/ 跨域 子域名不同(www/blog)
http://www.test.com:8080/ http://www.test.com:7001/ 跨域 端口号不同(8080/7001)

 

 

 

 

 

 

 

三、非同源限制

(1)无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB

(2)无法接触非同源网页的 DOM

(3)无法向非同源地址发送 AJAX 请求

 

四、服务端的跨域解决方案

1、JSONP

JSONP 是服务器与客户端跨源通信的常用方法。最大的特点是简单适用,兼容性好(兼容低版本IE),缺点是只支持 Get 请求,不支持 Post 请求。

核心思想:网页通过添加一个 <script> 元素,向服务器请求JSON数据、服务器接收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。

前端代码

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>JSONP</title>
        <script src="https://css.ssl.q1.com/jquery/jquery-1.11.1.min.js?v=2018051103"></script>
    </head>
    <body>
        <div id="btn">请求接口</div>
        <script>
            $('#btn').click(() => {
                $.ajax({
                    async: true,
                    url: "http://xxxxxx.dev.q1op.com/home/test",
                    type: "GET",
                    dataType: "jsonp", // 返回的数据类型,设置为JSONP方式
                    jsonp: 'callback', //指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback
                    jsonpCallback: 'handleResponse', //设置回调函数名
                    data: {
                        q: "javascript",
                        count: 1
                    },
                    success: function (response, status, xhr) {
                        console.log('状态为:' + status + ',状态是:' + xhr.statusText);
                        console.log(response);
                    }
                });
            });

            function handleResponse()
            {
                console.log('回调');
            }
        </script>
    </body>
</html>
View Code

后端代码:

namespace CorsTest.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class HomeController : ControllerBase
    {
        [HttpGet("test")]
        public IActionResult Test(string callback)
        {
            return Content($"{callback}(ok)");
        }
    }
}
View Code

执行结果:

 

2、CORS

 CORS是跨域资源分享(Cross-Origin Resource Sharing)的缩写,他是W3C标准,属于跨源AJAX请求的根本解决方法。

  (1) 普通跨域请求:只需服务器端设置 Access-Control-Allow-Origin

  (2)带cookie跨域请求,前后端都需要进行设置。

一个错误的案例

在服务端代码中 public void ConfigureServices(IServiceCollection services) 定义跨域解决方案

services.AddCors(options =>
{
    options.AddPolicy("CorsAllowAll", (builder) =>
    {
        builder.AllowAnyOrigin() // 允许任意来源的主机访问
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials();//处理 Cookie
    });
});

在 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 中 use上述方案(注 "CorsAllowAll" 可以定义为任何值,但需要上下一致)

app.UseCors("CorsAllowAll");

上述方案启动服务时会报错:

解决方案:

  根据请求是否需要携带Cookie来修改跨域方案配置。

      (1)请求设置不携带 Cookie

          

            此时,服务端无需设置  AllowCredentials()         

services.AddCors(options =>
{
    options.AddPolicy("CorsAllowAll", (builder) =>
    {
        builder.AllowAnyOrigin() // 允许任意来源的主机访问
        .AllowAnyMethod()
        .AllowAnyHeader();
        //.AllowCredentials();//处理 Cookie (当前端的 xhrFields: { withCredentials: false } 参数设置为false时,无需处理 Cookie)
    });
});

     (2)请求设置携带 Cookie

       

       此时,服务端需要 配置  AllowAnyOrigin()

services.AddCors(options =>
{
    options.AddPolicy("CorsAllowAll", (builder) =>
    {
        //这段解决 AllowAnyOrigin() 不能跟 AllowCredentials() 共用的问题
        builder = builder.SetIsOriginAllowed((host) => true);

        builder.AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials();//处理 Cookie (当前端的 xhrFields: { withCredentials: false } 参数设置为false时,无需处理 Cookie)
    });
});

   此案例前端完整代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>CORS</title>
        <script src="https://css.ssl.q1.com/jquery/jquery-1.11.1.min.js?v=2018051103"></script>
    </head>
    <body>
        <div id="btn">请求接口</div>
        <script>
            $('#btn').click(() => {
                $.ajax({
                    url: "http://xxxxxxx.dev.q1op.com/home/test",
                    type: "get",
                    crossDomain: true,
                    contentType: 'application/json',
                    xhrFields: { withCredentials: true },
                    success: function (data) {
                        console.log(data)
                    },
                    error: function (data) {
                        console.log(data)
                    }
                })
            });
        </script>
    </body>
</html>
View Code