Access-Control-Allow-Origin跨域问题

日常开发中,特别是如今,前后端分离甚至是前后端不同域,这种情况下进行数据交换就会出现跨域问题。

Cross-Origin Resource Sharing是允许客户端与托管在不同域上的API交互的机制。CORS的工作原理是要求服务器包含一组特定的标头信息,允许浏览器确定是否和何时允许跨域请求。

ajax无法访问django接口

一般出现这种情况的很大可能是出现在本地开发环境,甚至有可能使用pycharm运行django导致的。本人刚遇到这种问题也是一脸懵逼,麻蛋,浏览器正常访问,怎么一用ajax就直接走error方法出现network error,百度了很久仍然没有遇到跟我一样情况的,感觉是跨域问题,愣是没找到解决办法,想来想去,终于毛瑟顿开。

分析下,正常pycharm运行我们的django项目是默认走得80端口,使用127.0.0.1。问题就是出现在这个ip上。

127.0.0.1是回送地址,localhost是本地DNS解析的127.0.0.1的域名,在hosts文件里可以看到。

一般我们通过ping 127.0.0.1来测试本地网络是否正常。其实从127.0.0.1~127.255.255.255,这整个都是回环地址。这边还要

注意的一点就是localhost在了IPV4的是指127.0.0.1IPV6是指::1。当我们在服务器搭建了一个web服务器的时候如果我们

监听的端口时127.0.0.1:端口号 的 时候,那么这个web服务器只可以在服务器本地访问了,在别的地方进行访问是不行的。

127.0.0.1只可以在本地ping自己的,那么你监听这个就只可以在本地访问了)

然后我们来讲讲0.0.0.0,如果我们直接ping 0.0.0.0是不行的,他在IPV4中表示的是无效的目标地址,但是在服务器端它表示

本机上的所有IPV4地址,如果一个服务有多个IP地址(192.168.1.210.1.1.12),那么我们如果设置的监听地址是0.0.0.0

么我们无论是通过IP192.168.1.2还是10.1.1.12都是可以访问该服务的。在路由中,0.0.0.0表示的是默认路由,即当路由表中没有找到完全匹配的路由的时候所对应的路由。

如果以上内容把你说晕了,那么你就直接记住相让别人可以访问你那就绑定在0.0.0.0上,反之绑定在127.0.0.1

所以修改下你的项目运行属性

再次测试已经可以正常取到接口数据了,但是也许你会遇到下面这个新的问题。

跨域问题

1
Access to XMLHttpRequest at 'http://aaa.com/api/' from origin 'http://bbb.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

如果你的网站控制台出现了以下提示,很荣幸告诉你,你遇到跨域问题了。

Django REST framework官方文档中是这样描述关于跨域问题的,同时官方也给出了两种解决方案:

使用中间件

REST框架中处理CORS的最佳方法是在中间件中添加所需的响应头信息。这样可以确保CORS得到透明支持,而无需更改视图中的任何行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# cors_middleware.py
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()

def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response


class CORSMiddleware(MiddlewareMixin):
def process_response(self,request,response):
# 添加响应头

# 允许你的域名来获取我的数据
response['Access-Control-Allow-Origin'] = "*"

# 允许你携带Content-Type请求头
# response['Access-Control-Allow-Headers'] = "Content-Type"

# 允许你发送DELETE,PUT
# response['Access-Control-Allow-Methods'] = "DELETE,PUT"
return response


# setting.py
MIDDLEWARE = [
'app1.cors_middleware.CORSMiddleware',
]

使用第三方包

Otto Yiu维护着能在REST框架搭建的API下正常使用的django-cors-headers包。

安装第三方包

1
pip install django-cors-headers

配置安装包

1
2
3
4
5
INSTALLED_APPS = [
...
'corsheaders'
...
]

配置中间件

1
2
3
4
5
6
MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',#放到中间件顶部
'django.middleware.common.CommonMiddleware',
...
]

配置settings

1
2
3
4
5
6
7
8
9
10
11
12
13
CORS_ORIGIN_ALLOW_ALL = True # 允许任何域访问
# 或指定域/ip访问
CORS_ORIGIN_WHITELIST = [
"https://example.com",
"https://sub.example.com",
"http://localhost:8080",
"127.0.0.1:9000"
]
# 甚至可以使用正则限制域
CORS_ORIGIN_REGEX_WHITELIST = [
r"^https://\w+\.example\.com$",
]
# 以上设置一个即可

其他常用参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 在某些url上使用这个跨域中间件
CORS_URLS_REGEX = r'^/api/.*$'

# 允许的http请求
CORS_ALLOW_METHODS = [
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
]

# 允许的请求头
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]