浏览器的同源 跨域问题的解决方法

       说起跨域,开发过前后端的程序员都不陌生,但是大多数人还是知其然而不知其所以然。 在和别人讲对跨域的理解的时候,发现自己其实并不是特别熟悉。只是会用,为什么这么用,我说不清楚。所以还是再系统的学一下。

        情景:前端项目通过网络请求从后端项目中获取数据,后端显示访问正常,没有任何报错,而在前端却收不到数据,还会出现报错。遇见这种情况,很大可能是出现了跨域问题。那么跨域问题发生在前端与后端的哪个阶段? 

        

1、什么是跨域?

    跨域是前后端分离的项目绕不开的话题。 因为前端和后端是不同源的。 说到不同源。又需要讲一下同源策略

    同源策略,是指浏览器的同源策略, 它是浏览器最核心,也是最基本的安全功能。

    没有浏览器的同源策略,就不会有跨域的问题。

登录baidu.com (为了简便,利用其它网站的前端项目)按F12,打开console,   输入如下代码:

var xhr = new XMLHttpRequest();
xhr.open('GET', '跨域请求网址');
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responseText);
}

出现类似这样的报错:No 'Access-Control-Allow-Origin' header is present on the requested resource.

但是后端是能够正常接收到请求的, 如下图:

分析: 前后端分离的项目出现了报错,问题既不是出在前端,也不是出在后端。那么还剩下一种情况:浏览器

我们在浏览器输入网址时,浏览器会先向前端项目发起数据请求,然后前端项目向浏览器返回数据,而这些数据中,包含了让浏览器向后端继续获取数据的命令,这时,浏览器会执行这些命令,向后端项目获取数据请求,后端项目也会相应地将数据返回给浏览器,但是浏览器会选择拒绝接受此数据并报出产生跨域问题的错误信息。这个情况,就是浏览器同源策略起了作用。

二、跨域问题的解决思路

解决跨域问题,方案有很多,有的基于前端的配置, 有的是基于后端的配置。 还有的基于中间件的反向代理的方式。

1. 通过jsonp跨域  (基于前端配置)

    原理: <script>标签不受浏览器同源策略限制,比如在线引用jQuery, 其实也是一种跨域的实现:

<script src="http://code.jquery.com/jquery-latest.js"></script>

注意:jsonp 有很大的局限性,就是只能实现get请求

2. document.domain + iframe 跨域  (基于后端配置)

    原理:不同域指向的两个页面,都通过JS强制设置document.domain 为基础主域, 就可以实现同域。

(1)父窗口 www.domain.com/a.html:

<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>

  (2)  子窗口  child.domain.com/b.html:

<script>

注意:此方案仅限于主域相同,子域不同的跨域应用

3. CORS(跨域资源共享)(基于后端配置)

通过在服务端设置 Access-Control-Allow-Origin 即可解决跨域问题, 前端无需设置。

此方案是目前主流的跨域解决方案

CORS 是一个W3C标准

CORS的原理是只需要向响应头header 中注入Access-Control-Allow-Origin ,浏览器检测到header中有这个Access-Control-Allow-Origin,就可以进行跨域操作了。

CORS 允许浏览器向跨源服务器发送XMLHttpRequest 请求,从而克服Ajax 只能同源使用的限制

4. Nginx 代理跨域

 (1) Nginx 配置解决iconfont 跨域。浏览器跨域访问JS,CSS和Img等常规静态资源被同源策略许可,但iconfont字体文件(eot/otf/ttf/woff/svg)例外,此时可在Nginx的静态资源服务器中加入以下配置:

location / {
    add_header Access-Control-Allow-Origin *;
}

(2)Nginx 反向代理

原理: 通过Nginx 配置一个代理服务器(域名和domain1相同,端口不同) 做跳板机, 反向代理访问domain2接口。服务器调用HTTP接口只是使用HTTP协议,不会执行JS脚本,因为不需要同源策略,也就不存在跨域问题。

小结: 上面只介绍了4种常见的跨域解决方案。其实还存在着很多种解决方案。这些解决方案都可以总结出一个规律,那就是所有的解决方案都是在绕开一件事,那就是尽量绕开JS脚本中于网络请求有关的命令,浏览器对于JS脚本做网络请求的限制非常大,在浏览器中运行的JS脚本也因此不可以作为网络爬虫来运行,因为浏览器中运行的JS脚本在发送网络请求时,是不允许自定义协议头的。

三、解决跨域问题

    下面是基于后端项目的解决方案:

     (1) pip install django-cors-headers

     (2) 在settings 中注册模块, 增加中间件的配置代码, 能够跨域的白名单:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework',
    'corsheaders'
]




MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',  # 放到中间件顶部
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]


CORS_ORIGIN_ALLOW_ALL = False

CORS_ORIGIN_WHITELIST = (
   'http://192.168.9.2:8080',
   'https://ai.domain.com',
   "https://django.domain.com",
)

CORS_ALLOW_CREDENTIALS = True

CORS_ALLOW_HEADERS = (
    'lpt',
    'XMLHttpRequest',
    'content-type',
    'accept',
    'accept-encoding',
    'authorization',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值