• 跨域?同源?一次搞懂什么是跨域



    前言

    其实在我们用ajax传输数据时,很多时候都是在做跨域请求,如果没租过服务器的小伙伴可能没去捣鼓过这东西是什么。跨域其实在我们前后端数据交互非常常见,但是现在的模块化时代,一般我们不怎么会接触到跨域问题,因为很多事API已经帮我们解决了。接下来我就给大家好好捋清跨域是怎么回事。

    一、同源策略

    在先介绍跨域之前我觉得必须先普及同源策略的概念。
    什么是同源?
    如果两个页面的协议,域名和端口都相同,则两个页面具有相同的源。
    例如,下表给出了相对于http://www.test com/index.html页面的同源检测:
    在这里插入图片描述
    为了防止有小萌新连协议域名这种东西都不懂,在这里简单说明一下。
    协议就是我们网址上的http协议或者https协议,域名则是网址的名字,其实每台服务器的初始名字并不是这样的有辨识度,最开始大家的服务器都是像类似这种127.0.0.1编号的名字,后面为了让网站容易辨认,才弄出了像www.baidu.com,有辨识度的名字。端口就很容易了,就是服务器的接口。

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

    说白了就是浏览器规定,A网站的JavaScript,不允许和非同源的网站C之间,进行资源的交互,例如:
    ①无法读取非同源网页的CookieLocalStorageIndexedDB
    ②无法接触非同源网页的DOM
    ③无法向非同源地址发送Ajax请求

    二、跨域

    1.什么是跨域?

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

    比如下面两个域名不同,则他们之间的数据交互就属于跨域
    网页: http://www.test.com/index.html
    接口: http://www.api.com/userlist

    2.浏览器是如何对跨域进行拦截的?

    一图胜千言
    说白了就是浏览器允许发起跨域请求,但是,跨域请求回来的数据,会被浏览器拦截,无法被页面获取到。
    在这里插入图片描述

    3.如何实现跨域数据请求?

    解决跨域请求的方法有很多,我先来介绍一下两种最主要的解决方案,分别是JSONPCORS.

    JSONP:出现的早,兼容性好(兼容低版本IE)。是前端程序员为了解决跨域问题,被迫想出来的一种临时解决方案。缺点是只支持GET请求,不支持POST请求。

    CORS:出现的较晚,它是W3C标准,属于跨域Ajax请求的根本解决方案。支持GET和POST请求。缺点是不兼容某些低版本的浏览器。

    三、JSONP

    1.JSONP是什么?
    JSONP (JSON with Padding)是JSON的一种"使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

    2.JSONP的实现原理
    由于浏览器同源策略的限制,网页中无法通过Ajax请求非同源的接口数据。但是由于<script>标签不受浏览器同源策略的影响,可以通过src属性,请求非同源的js脚本。

    说白了,JSONP的实现原理,就是通过<script>标签的src属性,请求跨域的数据接口,并通过函数调用的形式,接收跨域接口响应回来的数据。

    所以JSONP的原理其实有一点套娃的意思,来使用回调函数去"骗过"浏览器。

    3.Jquery提供的JSONP接口
    jQuery提供的ajax()函数,除了可以发起真正的Ajax数据请求之外,还能够发起JSONP数据请求。用法和ajax差不多。
    例如:

    $.ajax({
    	url :'http://ajax.frontend.itheima.net:3006/api/jsonp?name=zs&age= 20',
    	//如果要使用$.ajax() 发起JSONP请求,必须指定datatype 为jsonp
    	dataType:'jsonp',
    	success: function(res) {
    		console. log (res)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    默认情况下,使用JQuery发起JSONP请求,会自动携带一个callback=jQueryxx的参数,JQueryxxx 是随机生成的一个回调函数名称。

    jQuery中的JSONP,也是通过<script> 标签的src属性实现跨域数据访问的,只不过, JQuery 采用的是动态创建和移除<script>标签的方式,来拨起JSONP数据请求。
    ●在发起JSONP请求的时候,动态向<header>中append一个<script> 标签;
    ●在JSONP请求成功以后,动态从<header>中移除刚才append进去的<script>标签;

    四、CORS

    CORS其实就是跨域资源共享,它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

    1、普通跨域请求:只需服务器端设置Access-Control-Allow-Origin
    2、带cookie跨域请求:前后端都需要进行设置

    前端JQuery.axjax设置,根据xhr.withCredentials字段判断是否带有cookie

    $.ajax({
       url: 'http://ajax.frontend.itheima.net:3006',
       type: 'get',
       data: {},
       xhrFields: {
           withCredentials: true    // 前端设置是否带cookie
       },
       crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie
    });
     
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。 整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信 没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附 加的请求,但用户不会有感觉。 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

    因此很多时候我们在用ajax发跨域请求而不会意识到的原因,就是后端服务器已经用CORS接口做好跨源通信了。

    CORS手动处理方法:

    app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*')
    res.header('Access-Control-Allow-Headers', 'Authorization,X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method' )
    res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PATCH, PUT, DELETE')
    res.header('Allow', 'GET, POST, PATCH, OPTIONS, PUT, DELETE')
    next();
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用cors包(封装):

    npm install cors --save-dev
    const cors = require('cors');
    app.use(cors());
    
    • 1
    • 2
    • 3

    我们这里需要注意的是在设置Origin字段时可以有两种情况:* 和一个域名
    在使用*(接受所有域名)的时候浏览器为了安全考虑是不会发送Cookie值的,使用一个域名的时候是可以的。但是在实际开发中我们通常只需要使用一个域名就可以完成业务了。


    总结

    跨域手段还有很多,比如用nginx或者websocket,像CORS不同后端的代码写法也不同,博主也还未完全掌握,其它内容未来会持续更新。
    在这里插入图片描述

  • 相关阅读:
    【牛客】SQL139 近三个月未完成试卷数为0的用户完成情况-窗口函数
    Leetcode_49:字母异位词分组
    制作一个企业网站——html华为官网购物商城项目的设计与实现
    计算机毕业设计基于SpringBoot的课程在线学习平台源码+数据库 程序设计/项目定制/调试部署
    Vue组件化编程(一)非单文件组件
    【【c语言康复训练-1】】
    Redis从青铜到王者,从环境搭建到熟练使用,看这一篇就够了,超全整理详细解析,赶紧收藏吧
    LeetCode - 160. 相交链表(C语言,配图)
    Linux中jar包实现自动重启、开机自启方案
    【第3章】MyBatis-Plus持久层接口之Service Interface(上)
  • 原文地址:https://blog.csdn.net/leoyongyuan/article/details/125565842