一、Django中设置
使用pip安装
pip install django-cors-headers
setting.py中设置
INSTALLED_APPS = [
...
'corsheaders'
]
MIDDLEWARE = [
'corsheader.middleware.CorsMiddleware', # 尽量放在csrf前面
...
]
添加中间件,需要注意放的位置,在SessionMiddleware后面以及CommonMiddleware前面
添加配置参数
#跨域增加忽略
CORS_ALLOW_CREDENTIALS = True # 允许携带cookie
CORS_ORIGIN_ALLOW_ALL = True #允许所有域名跨域,也可以在下面配置白名单
#白名单
# CORS_ORIGIN_WHITELIST = (
# 'http://127.0.0.1:8000',
# 'http://localhost:9528', #凡是出现在白名单中的域名,都可以访问后端接口
# )
#允许的请求头,不能用*,要写具体的请求头,不然Vue会跨域失败,在这里坑了我好久好久MD
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'x-csrftoken'
)
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
二、Vue中设置
Vue中如果要携带Cookies,在配置axios的时候需要设置允许携带cookie请求,两种方法都可以。
1、axios设置default参数
// 允许携带cookie请求
axios.defaults.withCredentials = true
2、或者创建实例的时候设置withCredentials: true
//1. 创建新的axios实例,
const service = axios.create({
// 公共接口--这里注意后面会讲
baseURL: 'http://10.0.0.101:8000/api/v1/',
// 超时时间 单位是ms,这里设置了3s的超时时间
timeout: 30 * 1000,
withCredentials: true
})
三、谷歌浏览器跨域Cookies带不到后端的坑
参考 VUE 在谷歌浏览器中无法识别存储的Cookie,以及跨域跳转
Firefox改Cookie的SameSite预设,Mozilla鼓励开发者测网站兼容性
- 我这里认证使用的cookies-sessionid的方式,所以跨域请求的时候需要带上cookies,但是配置了上面的参数后,请求可以访问到后端,但是cookies在后端一直带不过去。找了好久,发现是浏览器SameSite这个配置的问题。
SameSite可以有下面三种值:
None
浏览器会在同站请求、跨站请求下继续发送cookies,不区分大小写。
Strict
浏览器将只在访问相同站点时发送cookie。(在原有Cookies的限制条件上的加强,如上文“Cookie的作用域” 所述)
Lax
在新版本浏览器中,为默认选项,Same-site cookies 将会为一些跨站子请求保留,如图片加载或者frames的调用,但只有当用户从外部站点导航到URL时才会发送。如link链接
-
原因是Chrome升级到80版本之后cookie的SameSite属性默认值由None变为Lax,这也就造成了一些访问跨域cookie无法携带的问题。当开发者明确配置SameSite为None,同时还设定Secure属性使用HTTPS连线,才能够让Cookie可被跨站存取。
-
过去浏览器预设允许Cookie跨站存取,因此开发者不需要特别设定,但由于预设属性变更,现在网站开发者必须要明确设定SameSite与Secure属性,例如
response.setHeader("Set-Cookie", "HttpOnly;Secure;SameSite=None")
过去仰赖旧预设的网站才能正确运作,当网站没有正确配置这些属性,则功能就可能故障。 -
但是如果设置SameSite与Secure属性,那么就会强制需要https访问,还要再加上http转https的配置,实在是蛋疼。下面直接修改谷歌浏览器的SameSite配置来解决Cookies带不过去的问题
-
但是不可能每个人都修改浏览器配置呀,所以在生产环境可以使用nginx转发,可以在前端的nginx上,加上一层代理,比如匹配/api/v1,把请求转到后端的服务上,这样就不会有跨域的问题了。
1、打开chrome 输入 chrome://flags/ 搜索 SameSite by default cookies
2、找到SameSite by default cookies和Cookies without SameSite must be secure
3、将上面两项设置为 Disable
4、点击Relaunch
火狐浏览器设置跨域
1.进入火狐配置页进行设置
在地址栏输入:about:config
2.搜索”security.fileuri.strict_origin_policy”,并设置该项为false
3.重启浏览器
四、使用NGINX代理
如果上面修改了谷歌浏览器SameSite配置不生效的话,还可以使用NGINX代理来处理跨域问题。部分配置如下,在nginx服务器上,将默认的请求转到前端,将/api/v1/的请求转到后端
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
upstream vue {
server 10.0.0.1:9528;
}
upstream django {
server 10.0.0.107:8000;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://vue ;
}
location ~ /api/v1/ {
proxy_pass http://django;
}
}
然后把域名解析到nginx服务器的IP上,例如host文件里配置
10.0.0.107 wangxiaoyuvue.baidu.com
在vue的axios中,将baseurl设置为配置的域名,这样后端的API也会请求到nginx服务上进行代理
const service = axios.create({
baseURL: 'http://wangxiaoyuvue.baidu.com/api/v1/',
})
有个httponly的坑需要注意一下
- 我用的sessionid做验证,前面前后端的域名不同,进行登陆验证的时候,请求后端的API时,响应会在后端的地址上设置sessionid这个cookies
- 我返回的data信息里也有sessionid(我这里是从自己返回data里获取的,而不是从cookies里,因为默认设置的是httponly=true,在JS中获取不到),所以在验证成功后,会使用JS在前端的地址上也设置一下sessionid这个cookies,这个后面前端跨域请求的时候,才会把sessionid这个cookies带到后端。
- 并且,在vue的路由前置函数里,判断是否有sessionid,如果没有的话则跳转到登陆页。
- 但是,如果使用nginx代理后,前后端的域名是一样的,请求django的login登陆函数后,会直接设置sessionid这个cookies,并且httponly=true
- 如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性
- 需要再django的setting.py中设置
SESSION_COOKIE_HTTPONLY=False
,让django在设置cookies的时候,httponly=false
五、Vue配置代理
开发模式下使用Vue代理
如果用上面那种nginx里转发的方法的话,后端的域名如果写死了,因为是在同一个nginx里接收前后端的请求然后判断转到前端或者后端,在axios.defaults.baseURL=http://www.xxxapi.com/api/v1
里将后端的域名写死了
但是如果有多个前端域名的话,这个时候就很麻烦了,总不能跟着配置多个后端的域名吧。在开发模式下可以使用vue的代理方式。
修改aixos的baseURL前缀,这里不加具体的域名或者ip,这样会默认请求当前项目,可以匹配到代理的配置
axios.defaults.baseURL = '/api/v1/'
在vue.config.js中设置代理,匹配包含/api/v1的请求转到后端的域名地址
proxy: {
'/api/v1': {
target: 'http://www.xxxapi.com/',
changeOrigin: true, // 允许跨域
pathRewriter: {
// '': ''
}
}
},
注意:如果用的vue-element-admin这个框架,一定要把下面的before: require('./mock/mock-server.js')
这个注释掉,不然会请求项目之前设置的一些数据。
部署上去后发现代理失效了,这个代理只在dev模式下有效,所以在前端的nginx上还是得做转发
location ~ /api/v1/ {
proxy_pass http://django;
}
六、部署到机器上
这里用的vue-element-admin
git clone git@git.xxx
cd 项目地址
npm install --registry=https://registry.npm.taobao.org
npm install
npm run build:prod
然后把打包后的dist文件放到nginx,try_files $uri $uri/ /index.html;
这个表示如果找不到静态资源则把请求转给index.html
location / {
root /usr/local/dist;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
location ~ /api/v1/ {
proxy_pass http://django;
}