关于跨域的一些事

web前端开发中,我们经常需要访问除了源服务器(输出当前页面的服务器)外的服务,这时由于浏览器同源策略https://en.wikipedia.org/wiki/Same-origin_policy的限制,我们需要做很多额外的修改才能达到目的。而在web后端开发中,我们可以直接从一个服务器发送请求到另一个服务器,由于不存在浏览器做中介,所以可以很方便地进行通信,诞生了各种RPC框架,这些框架的底层通信模块常见的基本都是使用socket、HTTP、PB(Protocol Buffers)等通信协议。这篇文章只说在浏览器参与的跨域中的情况。

跨域分两种:跨子域和跨全域。从easydb.dtstack.com发送HTTPRequest到www.dtstack.com,这样的叫跨子域;从www.baidu.com发送HTTPRequest到www.dtstack.com,这样的叫跨全域。

关于跨域通信,目前已经有了很多方法,最常见的就是JSONP,但JSONP和
Ajax并不相同。Ajaxhttps://zh.wikipedia.org/zh/AJAX通常都是通过新建XMLHTTPRequest(IE下还有类似XMLDomainRequest)来创建请求,而JSONP的本质其实是利用向DOM中插入script标签来“触发”请求,因此JSONP不会受到浏览器同源策略的影响。因此,许多web service都是通过JSONP实现。但JSONP任何人都能调用,无形中放大了服务器的潜在bug危害,因此我们还会时不时地用到Ajax。接下来我们就来聊聊Django中常见的Ajax跨域解决方案。

跨子域

解决跨子域有纯前端的方案,比如从easydb.dtstack.com跨子域访问www.dtstack.com,只需要在JS中设置
document.domain = 'dtstack.com'
然后正常发送请求就行了。

也有前后端配合的方案,可以参考跨全域的方案。

跨全域

跨全域通信的关键在于被访问的服务器允许访问方进行访问。

因此,一般发送跨域请求时,浏览器会“询问”服务器是否允许当前请求进行访问,“询问”的方式是通过发送一个OPTIONS请求,这时被访问服务器需要返回一些信息表示是否允许,这些信息一般放在HTTP header中。这样,如果被访问服务器返回表示允许访问的HTTP header,那么浏览器就会发送用户创建的跨域请求,这样就完成了跨域通信了。

基本原理弄清楚了,接下来就是实现细节了。

Django中,我们可以添加一个中间件来为跨域请求设置恰当的HTTP header。首先创建一个cross_domain_middleware.py文件

from dtuic.settings import ALLOWED_HOSTS_FOR_MIDDLEWARE

class CrossDomainMiddleware(object):

    def process_response(self, request, response):

        origin = request.META.get('HTTP_ORIGIN')
        allowed_hosts = self.get_allowed_hosts(request)

        if origin in allowed_hosts or '*' in allowed_hosts:
            response["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept, Key, source"
            response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS, DELETE, PUT"
            response["Access-Control-Allow-Origin"] = origin
            response["Access-Control-Max-Age"] = "1000"
            response['Access-Control-Allow-Credentials'] = "true"

        return response

    def get_allowed_hosts(self, request):
        hosts = []
        for host in ALLOWED_HOSTS_FOR_MIDDLEWARE.split(','):
            host = host.strip()
            if host != '*':
                host = "{}://{}".format(request.scheme, host)

            hosts.append(host)

        return hosts

,同时在settings文件中添加

ALLOWED\_HOSTS\_FOR\_MIDDLEWARE = "www.baidu.com, www.whatever.com"

,最后在Django的middleware配置中添加我们新建的cross_domain_middleware

MIDDLEWARECLASSES = (
'dtuic.middleware.crossdomainmiddleware.CrossDomainMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
...
)

放在最前面,见https://docs.djangoproject.com/en/1.10/ref/settings/#allowed-hosts

目前ALLOWED_HOSTS_FOR_MIDDLEWARE 只支持多个域名显示配置,也可以使用正则动态匹配。

注意Django中的ALLOWED_HOSTS并不是为了跨域的配置,而是针对全局请求访问的一个配置,如果直接覆盖,可能会导致全站400,本地开发时由于Django的调适标识Debug都为True,Django这时是默认允许所有请求访问的,所以即使覆盖了ALLOWED_HOSTS也不会有问题,而到了线上,Debug切换到False,就会有“惊喜”了。

参考:
http://www.html5rocks.com/en/tutorials/cors/

时间: 2024-12-31 16:16:25

关于跨域的一些事的相关文章

html5 postMessage解决跨域、跨窗口消息传递

平时做web开发的时候关于消息传递,除了客户端与服务器传值还有几个经常会遇到的问题 1.页面和其打开的新窗口的数据传递 2.多窗口之间消息传递 3.页面与嵌套的iframe消息传递 4.上面三个问题的跨域数据传递 postMessage() 这些问题都有一些解决办法,但html5引入的message的API可以更方便.有效.安全的解决这些难题.postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档.多窗口.跨域消息传递. postMessage(data,

jQuery中getJSON跨域原理详解

jQuery中getJSON跨域原理详解  前几天我再开发一个叫 河蟹工具条 的时候,其中有个功能就是获取本页面的短网址. 这个想法是好的,可是在我付诸于行动的时候,发现这个需要跨域. 起初我的想法就是,跨域的最简单的方法就是增加一个script标签,因为script标签是允许跨域的. 但是问题又来了,对方的API返回的是个json对象,用script标签只能执行,却不能获取到里面的东西,也就是说返回的东西是不可控的. 随后我就想到了jQuery中的getJSON的方法,学习了一下,没想到里面的

Angular通过CORS实现跨域方案

以前有一篇很老的文章网上转了很多,包括现在如果你百度"跨域"这个关键字,前几个推荐的都是"Javascript跨域总结与解决方案".看了一下感觉手段有点陈旧了,有一些比如document.domain还有iframe的解决方案委实"丑陋"一些,感觉不再适用于现在一些项目中. 就拿iframe来说作为一个前端工程师,我极为讨厌iframe这种东西.它不光增加了性能上的高负荷,同时也不利于掌控. 在Angular应用中实现跨域的方式相对简单,基本上通

利用iframe实现ajax跨域通信的实现原理(图解)_AJAX相关

在漫长的前端开发旅途上,无可避免的会接触到ajax,而且一般情况下都是用在同一域下的ajax请求:但是如果请求是发生在不同的域下,请求就无法执行,并且会抛出异常提示不允许跨域请求,目前我没有找到明确的资料说明这是为什么,我觉得应该是出于安全性的考虑吧.纵然如此,要实现跨域访问的话,方法还是有的,而且不只一种,在这里介绍其中一种解决方案:如何利用iframe完成ajax的跨域请求. 如下图所示:域a.com的页面request.html(即http://a.com/request.html)里面嵌

jQuery.form插件的使用及跨域异步上传文件_jquery

先说明白 这个跨域异步上传功能我们借助了Jquery.form插件,它在异步表单方面很有成效,而跨域我们会在HTTP响应头上添加 access-control-allow-method,当然这个头标记只有IE10,火狐和谷歌上支持,对于IE10以下的浏览器来说,我们就不能用这种方式了,我们需要换个思路去干这事,让服务端去重写向我们的客户端,由客户端(与文件上传页面在同域下)来返回相关数据即可. 再做事 1 Jquery.form的使用 <form method="post" ac

基于Jquery插件实现跨域异步上传文件功能_jquery

先说明白 这个跨域异步上传功能我们借助了Jquery.form插件,它在异步表单方面很有成效,而跨域我们会在HTTP响应头上添加access-control-allow-method,当然这个头标记只有IE10,火狐和谷歌上支持,对于IE10以下的浏览器来说,我们就不能用这种方式了,我们需要换个思路去干这事,让服务端去重写向我们的客户端,由客户端(与文件上传页面在同域下)来返回相关数据即可. 再做事 1 Jquery.form的使用 <form method="post" act

深入分析Javascript跨域问题_javascript技巧

跨域是什么? 假设a.com/get.html需要获取b.com/data.html中的数据,而这里a.com和b.com并不是同一台服务器,这就是跨域跨域会涉及到Javascript的同源策略,简单来说就是为了保护网站的安全,不被外域(非同源)服务器的js修改本网站内容. 引用一个表格,看一下引起跨因的条件有哪些: 但是有时候我们确实需要这么做,那么我们有哪些方法呢? 1.JsonP 提到跨域不能不先提及jsonp.jsonp其实是JavacScript Object Notation wit

父页面_子页面跨域访问

问题描述 www.a.com中有a.jsp里面有一个链接<ahref="www.b.com/b.jsp">打开子页面</a>b.jsp就相当于子页面b.jsp中有一个保存按扭,点击后返回记录ID现在想在b.jsp返回的记录ID到a.jsp中后,b.jsp页面关闭.同时也能在a.jsp中得到这个记录ID的值,js中有什么好的方法没?ajaxxmlhttp用过了,会出现得不到值的问题不知有没有什么好的方法,请教大侠们了. 解决方案 解决方案二:b.jsp里给个连接&

js利用iframe实现跨域通信例子

为了方便演示跨域效果,先在 hosts 文件中加上以下内容: 127.0.0.1 www.myapp.com 127.0.0.1 sample.myapp.com 127.0.0.1 www.otherapp.com 下面我们就开始讨论如何使用iframe进行跨域通信,这里主要介绍以下几种方案: document.domain .URL.hash . Cross-fragment . Window.name . postMessage . document.domain 如果 A 源和 B 源具