使用axios时,添加自定义的headers字段,出现跨域的解决方案

一. 背景

在做毕设时,总会遇到新的问题,这不,它又来了,这次的需求是在发送GET请求时,为了确保用户具有发送该API的权限,需要在headers头部中增加一个permission字段便于后端校验。

如下是vue中使用axios发送请求,并在headers中添加permission字段。

1
2
3
const res = await this.$http.get('/seller/chsc/apis/commodity/', {
headers: { Permission: this.permission },
})

二 问题

刷新浏览器,芜湖~,飘了3条红,仔细一看,发现是跨域处出现了问题, 错误原因是因为permissions不被Access-Control-Allow-Headers所允许,由于Access-Control-Allow-Headers出现在响应体中,所以由后端来定义。故而,只需要修改后端的代码即可。

{width=90%}


三 解决方法

我后端开发采用Django,使用了CorsMiddleware中间件,进入CorsMiddleware源码,在process_response函数中可以看到响应的响应头部字段的设置。

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
37
38
39
40
41
42
43
44
45
46
47
def process_response(self, request, response):
"""
Add the respective CORS headers
"""
enabled = getattr(request, "_cors_enabled", None)
if enabled is None:
enabled = self.is_enabled(request)

if not enabled:
return response

patch_vary_headers(response, ["Origin"])

origin = request.META.get("HTTP_ORIGIN")
if not origin:
return response

# todo: check hostname from db instead
url = urlparse(origin)

if conf.CORS_ALLOW_CREDENTIALS:
response[ACCESS_CONTROL_ALLOW_CREDENTIALS] = "true"

if (
not conf.CORS_ALLOW_ALL_ORIGINS
and not self.origin_found_in_white_lists(origin, url)
and not self.check_signal(request)
):
return response

if conf.CORS_ALLOW_ALL_ORIGINS and not conf.CORS_ALLOW_CREDENTIALS:
response[ACCESS_CONTROL_ALLOW_ORIGIN] = "*"
else:
response[ACCESS_CONTROL_ALLOW_ORIGIN] = origin

if len(conf.CORS_EXPOSE_HEADERS):
response[ACCESS_CONTROL_EXPOSE_HEADERS] = ", ".join(
conf.CORS_EXPOSE_HEADERS
)

if request.method == "OPTIONS":
response[ACCESS_CONTROL_ALLOW_HEADERS] = ", ".join(conf.CORS_ALLOW_HEADERS)
response[ACCESS_CONTROL_ALLOW_METHODS] = ", ".join(conf.CORS_ALLOW_METHODS)
if conf.CORS_PREFLIGHT_MAX_AGE:
response[ACCESS_CONTROL_MAX_AGE] = conf.CORS_PREFLIGHT_MAX_AGE

return response

说明:

由于我们使用axios+跨域,通常无论GET或者POST请求会发送两次。第一次请求是OPTIONS请求,表示询问是否允许跨域,如果允许则发送第二次请求(GET或者POST),其中第一次请求返回的响应体中包含了允许跨域的请求头,请求方法和请求源,请求最大生存时间等,第二次请求只有都满足第一次请求响应体中的条件,才会成功发送,否则会产生跨域错误问题。

我们可以在源码找到这行代码response[ACCESS_CONTROL_ALLOW_HEADERS] = “, “.join(conf.CORS_ALLOW_HEADERS),我们可以去找到CORS所允许的头部,

1
2
3
@property
def CORS_ALLOW_HEADERS(self):
return getattr(settings, "CORS_ALLOW_HEADERS", default_headers)
1
2
3
4
5
6
7
8
9
10
11
default_headers = (
"accept",
"accept-encoding",
"authorization",
"content-type",
"dnt",
"origin",
"user-agent",
"x-csrftoken",
"x-requested-with",
)

如果我们在settings.py文件中没有自己定义CORS_ALLOW_HEADERS元祖,则使用默认的default_headers,为了避免修改框架源码,我们可以自己定义,在CORS_ALLOW_HEADERS元祖中添加permission即可。添加之后,请求可以正常发送。