Django Vue 跨域问题

一、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;
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值