之前有一个用Django框架写的网站,前端贪图方便直接用html+css写的,自然很丑,于是后来使用Vue框架+Element-ui组件来重构前端,使得网站前后端分离。
如何组合Django后端和Vue前端,我参考的是这篇博客整合 Django + Vue.js 框架快速搭建web项目,写的非常好,完整讲述了如何在Django项目中新建Vue项目,如何进行Django与Vue间的数据交互,以及如何将二者整合在一起。但是在“Django与Vue间的数据交互”这一部分,我踩了一个坑“No ‘Access-Control-Allow-Origin’ header is present on the requested resource. ”
文章中说这是因为Django和Vue运行的端口号不同,跨域问题,也给出了解决方法,但是写的十分简洁,而且用上去也还是没有解决到这个问题,于是我网上查了很久,试了很多方法,最终才解决了这个问题。下面详细讲解如何解决这个问题。
当开发模式采取前后端分离式开发时,通常情况下,前端和后端是运行不同的ip或者port下分别进行开发的,这就会导致出现跨域问题。跨域问题是因为浏览器有同源策略
的限制,不是同源的脚本不能操作其他源下面的对象。
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
简单的来说:协议、IP、端口三者都相同,则为同源
所以在本地开发项目时,Django后端运行在http://127.0.0.1:8000
,而Vue前端运行在http://127.0.0.1:8080
上,二者端口号不同,不同源,因此产生了跨域问题。
网上主要有两种解决方法,分别是在前端解决和在后端解决。参考Django+vue跨域问题解决。
参考vue2.0 proxyTable配置,解决跨域 webpack+vue-cil 中proxyTable配置接口地址代理 【vuejs开发】如何在vue里面优雅的解决跨域,路由冲突问题!超详细
既然跨域是因为不同源,那我同源不就完事儿了,但是后端请求地址不可能改变,所以可以在前端和后端的中间加一层代理(代理与后端是同源的),前端通过代理访问后端。
首先我的Vue前端的当前网页的地址是http://127.0.0.1:8080/JieHe_NetData
,我要向Django后台请求数据的地址是http://127.0.0.1:8000/api/showdata?disease=JieHe
。
webpack配置vue 的 proxyTable解决跨域的解决方法是打开Vue项目的config目录下的index.js 文件,proxyTable中加入以下内容:
proxyTable: {
'/api': {
target: 'http://127.0.0.1:8000/',
changeOrigin: true,
// pathRewrite: {
// '^/api': ''
// }
}
},
这个配置的意思是,当我的请求地址http://127.0.0.1:8000/api/showdata?disease=JieHe
中包含有/api
路径时,就触发代理,相当于变成由http://127.0.0.1:8000/
这个地址的代理主机发送这个请求,这样自然就能不会产生跨域问题了。注意这里我没有写pathRewrite,因为我的路径本身就是带有api
的,我所有向后台请求数据的接口都带有api
,不需要替换掉。
参考Django+vue跨域问题解决
后端出于安全考虑,有跨域限制,可以这样配置来取消这个限制:
安装django-cors-headers
pip install django-cors-headers
配置Django的settings.py文件
INSTALLED_APPS = [
...
'corsheaders',
...
]
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware', # 注意顺序
...
)
#跨域增加忽略
CORS_ORIGIN_ALLOW_ALL = True
然而我分别尝试了以上两种方法,都没有解决问题。后来我把Vue的请求地址从http://127.0.0.1:8000/api/showdata?disease=JieHe
换成http://localhost:8000/api/showdata?disease=JieHe
后竟然就解决了问题?我仍未想明白这到底是什么原理。而且我要同时用上前端和后端的方法才行,缺一不可,这个也没想明白为什么。
localhost与127.0.0.1的区别:
localhost:不通过网卡传输,不受网络防火墙和网卡相关的限制。
127.0.0.1:通过网卡传输,依赖网卡,并受到网卡和防火墙相关的限制。
localhost访问时,系统带着本机当前的用户权限去访问,而用ip的时候,等于本机是通过网络再去访问本机,可能涉及到网络用户的权限。所以一般设置程序是localhost是最好的,localhost不会解析成ip也不会占用网卡,网络资源。
另外,我也明白一个道理,就是一般设置程序是localhost是最好的,localhost不会解析成ip也不会占用网卡,网络资源。
下面再详细记录一下我解决问题的整个过程:
首先我Vue前端页面的请求是这样的:
export default {
data () {
return {
message: "样例"
}
},
mounted: function() {
this.get_data_from_backend()
},
methods: {
get_data_from_backend () {
this.$http.get('http://localhost:8000/api/showdata?disease='+'JieHe')
.then((response) => {
var res = JSON.parse(response.bodyText)
window.console.log(res)
})
},
}
}
Django后端view.py中对应的处理函数的返回数据是这样的:
def showdata(request):
disease = request.GET.get('disease')
print('disease1=', disease)
key_list, value_list = getNetData(disease)
xList=key_list
yList=value_list
return JsonResponse({'disease': json.dumps(disease),
'xList': json.dumps(xList),
'yList': json.dumps(yList),
'disease_name':disease} )
用Get方式请求数据。
首先是后端方面安装django-cors-headers,然后修改seeting.py
然后前端方面,修改config/index.js
然后就能成功请求数据了,F12打开console: