百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

一文带你理清同源和跨域

off999 2025-02-07 18:43 15 浏览 0 评论

1、概述

前后端数据交互经常会碰到请求跨域,什么是跨域,为什么需要跨域,以及常用有哪几种跨域方式,这是本文要探讨的内容。

同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

同源策略是一种约定,它是浏览器最核心也是最基本的安全功能。出于安全考虑,浏览器限制从JS脚本发起的跨源HTTP请求。

通俗的理解:浏览器规定,A 网站的 JavaScript,不允许和非同源的网站 C 之间,进行资源的交互,例如:

①无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB。

②无法接触非同源网页的 DOM。

③无法向非同源地址发送 Ajax 请求。

同源指的是两个 URL 的协议、域名、端口一致,反之,则是跨域。出现跨域的根本原因:浏览器的同源策略不允许非同源的 URL 之间进行资源的交互。

例如网页(
http://www.test.com/index.html)和接口(
http://www.api.com/userlist),非同源的URL,浏览器允许发起跨域请求,但是,跨域请求回来的数据,会被浏览器拦截,无法被页面获取到。

2、为什么要跨域?

跨域是浏览器受同源(协议、域名、端口)策略的限制,不允许不同源的站点之间进行某些操作(如发送ajax请求,操作dom,读取cookie),如果不进行特殊配置是不能操作成功的,并且控制台会报如下跨域错误:

`No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxxxxx' is therefore not allowed access

跨域的根本原因是浏览器的“同源策略”,同源 就是【协议+域名+端口号】相同,即为同源,只能向同源的服务发起AJAX请求。

源1

源2

是否同源

a.com

b.com

不同源,域名不同

http://a.com

https://a.com

不同源,协议不同

a.com:80

a.com:443

不同源,端口不同

gg.com

a.gg.com

不同源,子域名不同

a.com/ss

a.com/s2

同源

可通过location.originwindow.origin获取当前文档的源

为什么要同源呢?

这是浏览器故意设计的,是浏览器的基本安全策略,否则会很容易受到XSS、CSRF攻击。只能向同源的服务发起AJAX请求,不可跨域请求,会被浏览器拦截。

有哪些限制规则呢?

  • ? 访问其他源的图片、CSS、JS是可以的,允许

    JSONP的实现:

    function jsonp(url, args, cbName) {
      return new Promise((resolve, reject) => {
        const ele = document.createElement('script');
        window[cbName] = (data) => {
          resolve(data);
          document.body.removeChild(ele);
        }
        args = { ...args, callback: cbName };
        ele.src = `${url}?${Object.keys(args).map(k => `${k}=${args[k]}`).join('&')}`;
        document.body.appendChild(ele);
      });
    }
    //使用,api为360的公开接口
    jsonp('https://sug.so.360.cn/suggest', { format: 'jsonp', word: 'china' }, 'search')
      .then(function (data) {
        console.log(data)
      });

    3.2、CORS跨域

    CORS是什么?—— 跨域资源共享 (cross-origin resource sharing),让AJAX可以跨域访问数据。这是为了满足跨域请求的需求,W3C新增加的特性,需要服务端的支持,不支持IE8/9。

    当浏览器发送一个跨域请求时,它会首先发送一个预检请求(OPTIONS请求),检查后端是否支持跨域请求。这个预检请求会包含一些CORS相关的HTTP头,如Origin、
    Access-Control-Request-Method和
    Access-Control-Request-Headers。后端收到预检请求后,会检查请求中的Origin头,与自己在CORS配置中设置的allowedOrigins进行对比,如果匹配成功,就会在响应中设置相应的CORS头,如
    Access-Control-Allow-Origin、
    Access-Control-Allow-Methods和
    Access-Control-Allow-Headers等。

    一旦预检请求通过,浏览器就会发送实际的跨域请求。在接收到实际请求的响应后,浏览器会再次检查响应中的CORS头,确保它们与预检请求中的设置一致。如果一切正常,浏览器就会允许前端JavaScript代码访问响应中的数据。

    通过这种方式,后端通过显式配置CORS参数,告知浏览器哪些源有权访问其资源,从而实现了跨域访问的功能。这既保证了安全性(只允许指定的源进行访问),又提供了灵活性(可以根据需要配置不同的CORS策略)。

    根据请求方式,浏览器将CORS分为两种情况:

    • 简单请求(安全请求):只支持GET、POST、HEAD,Header只支持部分字段。
    • 复杂请求(其他请求):简单请求以外的其他跨域请求。

    简单请求

    基本原理就是在请求头加入一个身份来源标识,服务端根据这个标识来判等是否允许访问,如果允许则给一个允许的标记并返回响应。

    • 只支持GET、POST、HEAD。
    • header —— 我们仅能设置基础的安全字段:
      • Accept
      • Accept-Language
      • Content-Language
      • Content-Type 的值为 application/x-www-form-urlencoded,multipart/form-data 或 text/plain。

    具体过程比较简单,前端只要在Header加入“Origin”即可:

    • 请求头Header加入要跨域的源:origin:http://www.main.com
    GET /api HTTP/1.1
    Origin: http://www.main.com             //本次请求来自哪个源
    Host: http://www.third.com              //请求的第三方API
    Accept-Language: en-US
    Connection: keep-alive
    User-Agent: Mozilla/5.0
    ...
    • 服务端收到请求后检查Origin,如果同意请求则正常响应,同时在响应的Header中加入特殊的“Access-Control-Allow-Origin”字段,申明支持的源,也可以用“*”表示支持任何源访问。
    • 浏览器收到响应后会检查“Access-Control-Allow-Origin”,和当前源对比,如果不合法则会报错——跨域。
    Access-Control-Allow-Origin: http://www.main.com        //请求允许的源
    Access-Control-Allow-Credentials: true                          //是否允许cookie,cors默认不发送cookie,如果要发送,还需AJAX中设置withCredentials
    Access-Control-Expose-Headers: Content-Length,API-Key   //如果客户端想要访问其他非安全字段,则需要服务端明确定义哪些Header字段暴露出来
    Content-Type: text/html; charset=utf-8

    复杂请求

    不是简单请求的都称为复杂请求(非简单请求),如请求方法是PUT、DELETE,或Content-Type=application/json。相比于简单请求,复杂请求多了一次预请求。

    预请求

    • 正式发送请求前,浏览器会自动发送一个预请求,问问服务端是否允许本次请求,如果回应允许才正式发送请求,后面就和简单请求相同了。
    • 预请求及其响应都没有body,采用OPTIONS方法。

    JSONP 与`CORS 的对比

    JSONP 是很早很成熟的解决方案,但是,只能进行 GET 请求,无法实现上传数据等操作。

    反观:CORS 虽然分 预请求非预请求 ,但是,无疑支持的功能是非常强大的 !!!

    3.3、Nginx反向代理

    跨域是浏览器的保护机制,如果绕过浏览器,使用代理服务器去请求目标服务器上的数据,就不会受跨域影响。因此前端可以通过脚手架或webpack配置devSever下的proxy选项,将/api开头的请求转发到真实服务器上。

    在生产环境下也可以使用nginx配置反向代理来解决跨域。

    Nginx 则是通过反向代理的方式,(这里也需要自定义一个域名)这里就是保证我当前域,能获取到静态资源和接口,不关心是怎么获取的。

    配置下 hosts

    127.0.0.1 local.test

    配置 nginx

    server {
            listen 80;
            server_name local.test;
            location /api {
                proxy_pass http://localhost:8080;
            }
            location / {
                proxy_pass http://localhost:8000;
            }
    }

    对于前端开发而言,大部分的跨域问题,都是通过代理解决的

    代理适用的场景是:生产环境不发生跨域,但开发环境发生跨域

    4、小结

    因为同源是浏览器的限制,跨域的方法无非就是绕过,或采用CORS。

    跨域方案

    基本原理

    是否需要服务端支持

    JSONP

    借助

    相关推荐

    如何理解python中面向对象的类属性和实例属性?

    类属性和实例属性类属性就是给类对象中定义的属性通常用来记录与这个类相关的特征类属性不会用于记录具体对象的特征类属性的理解:类属性是与类自身相关联的变量,而不是与类的实例关联。它们通...

    Java程序员,一周Python入门:面向对象(OOP) 对比学习

    Java和Python都是**面向对象编程(OOP)**语言,无非是类、对象、继承、封装、多态。下面我们来一一对比两者的OOP特性。1.类和对象Java和Python都支持面向对象...

    松勤技术精选:Python面向对象魔术方法

    什么是魔术方法相信大家在使用python的过程中经常会看到一些双下划线开头,双下划线结尾的方法,我们把它统称为魔术方法魔术方法的特征魔术方法都是双下划线开头,双下划线结尾的方法魔术方法都是pytho...

    [2]Python面向对象-【3】方法(python3 面向对象)

    方法的概念在Python中,方法是与对象相关联的函数。方法可以访问对象的属性,并且可以通过修改对象的属性来改变对象的状态。方法定义在类中,可以被该类的所有对象共享。方法也可以被继承并重载。方法的语法如...

    一文带你理解python的面向对象编程(OOP)

    面向对象编程(OOP,Object-OrientedProgramming)是一个较难掌握的概念,而Python作为一门面向对象的语言,在学习其OOP特性时,许多人都会对“继承”和“多态”等...

    简单学Python——面向对象1(编写一个简单的类)

    Python是一种面向对象的编程语言(ObjectOrientedProgramming),在Python中所有的数据类型都是对象。在Python中,也可以自创对象。什么是类呢?类(Class)是...

    python进阶突破面向对象——四大支柱

    面向对象编程(OOP)有四大基本特性,通常被称为"四大支柱":封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)和抽象(Abstrac...

    Python学不会来打我(51)面向对象编程“封装”思想详解

    在面向对象编程(Object-OrientedProgramming,简称OOP)中,“封装(Encapsulation)”是四大核心特性之一(另外三个是继承、多态和抽象),它通过将数据(属性)和...

    Python之面向对象:对象属性解析:MRO不够用,补充3个方法

    引言在前面的文章中,我们谈及Python在继承关系,尤其是多继承中,一个对象的属性的查找解析顺序。由于当时的语境聚焦于继承关系,所以只是简要提及了属性解析顺序同方法的解析顺序,而方法的解析顺序,在Py...

    Python之面向对象:通过property兼顾属性的动态保护与兼容性

    引言前面的文章中我们简要提及过关于Python中私有属性的使用与内部“名称混淆”的实现机制,所以,访问私有属性的方法至少有3种做法:1、使用实例对象点操作符的方式,直接访问名称混淆后的真实属性名。2、...

    Python之面向对象:私有属性是掩耳盗铃还是恰到好处

    引言声明,今天的文章中没有一行Python代码,更多的是对编程语言设计理念的思考。上一篇文章中介绍了关于Python面向对象封装特性的私有属性的相关内容,提到了Python中关于私有属性的实现是通过“...

    Python中的私有属性与方法:解锁面向对象编程的秘密

    Python中的私有属性与方法:解锁面向对象编程的秘密在Python的广阔世界里,面向对象编程(OOP)是一种强大而灵活的方法论,它帮助我们更好地组织代码、管理状态,并构建可复用的软件组件。而在这个框...

    Python 面向对象:掌握类的继承与组合,让你的代码更高效!

    引言:构建高效代码的基石Python以其简洁强大的特性,成为众多开发者首选的编程语言。而在Python的面向对象编程(OOP)范畴中,类的继承和组合无疑是两大核心概念。它们不仅能帮助我们实现代码复用,...

    python进阶-Day2: 面向对象编程 (OOP)

    以下是为Python进阶Day2设计的学习任务,专注于面向对象编程(OOP)的核心概念和高阶特性。代码中包含详细注释,帮助理解每个部分的实现和目的。任务目标:复习OOP基础:类、对象、继...

    外婆都能学会的Python教程(二十八):Python面向对象编程(二)

    前言Python是一个非常容易上手的编程语言,它的语法简单,而且功能强大,非常适合初学者学习,它的语法规则非常简单,只要按照规则写出代码,Python解释器就可以执行。下面是Python的入门教程介绍...

    取消回复欢迎 发表评论: