1. 前后端分离开发
为了适应软件开发工程化趋势的要求, 目前越来越多的公司开始采用"前后端分离"的开发模式,这样开发的好处很多, 比如开发人员的分工更加细化,便于提供开发效率等. 但是只要采用了前后端分离的开发模式, 那么在请求后端数据时, 都会遇到跨域的问题.
1.1. 跨域问题的本源
跨域,是指浏览器不能执行其它网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript实施的安全限制。
所谓同源,就是域名、协议、端口均相同。举个例子:
http://www.123.com/index.html 调用 http://www.123.com/abc.do (非跨域)
http://www.123.com/index.html 调用 http://www.456.com/abc.do (主域名不同:123/456,跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.do (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.do(端口不同:8080/8081,跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.do (协议不同:http/https,跨域)
1.2. 实际开发中跨域问题解决:
在实际开发中遇到的跨域问题大致分为两类:
- 开发人员前端和后端都可以控制, 那么这种情况下, 解决跨域问题既可以采用后端解决, 也可以采用前端解决;
- 开发人员只能控制前端, 后端是调用别人已经开发部署的资源. 这种情况下, 只能通过前端来解决跨域问题.
本文以目前比较流行的前后端分离开发方案–Vue + Django, 分别给出跨域问题的解决方案.
2. 跨域问题的解决方案
随着互联网的发展,同源策略严重影响了项目之间的连接,尤其是大项目,需要多个域名配合完成,因此W3C推出了CORS,即Cross-origin resource sharing(跨来源资源共享)。CORS的基本思想就是使用额外的HTTP头部让浏览器与服务器进行沟通,从而决定是否接受跨域请求。
CORS需要浏览器和服务器同时支持,目前,所有浏览器都支持该功能。对于开发者来说,CORS通信与同源的AJAX通信没有区别,代码完全一样。浏览器在跨域访问时,会自动添加HTTP头信息,或者发起预检请求,用户对此毫无感知。因此是否支持跨域请求,关键在于服务器是否做了CORS配置,允许跨域访问。
因此, 所谓的前端解决方案, 本质是做的一层代理.
2.1. 服务端解决方案
服务端使用Django+ restframework提供项目API接口. 在解决跨域问题时按照如下处理:
- 安装
django-cors-headers
, 在命令行终端使用pip
工具完成
pip install django-cors-headers -i https://pypi.tuna.tsinghua.edu.cn/simple
- 对项目进行设置, 在项目的
settings
中进行
- 添加应用, 找到
INSTALLED_APPS
, 添加corsheaders
, 代码如下:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'home',
]
- 添加中间件, 找到
MIDDLEWARE
, 添加CorsMiddleware
, 注意一定要写在所有中间件的头部:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
- 开启跨域接受跨域请求, 添加白名单. 添加如下设置:
CORS_ALLOW_CREDENTIALS = False
CORS_ORIGIN_ALLOW_ALL = True
完成上述模块安装和项目配置后, 跨域问题服务端就解决了, 这个服务器可以接收任何前端应用的数据访问请求.
2.2. 前端的解决方案
当前端采用Vue框架进行开发时, 如果服务端我们没有办法控制, 就只能从前端着手进行解决.
- 在vue项目根目录下建立
vue.config.js
文件.代码如下:
module.exports={
devServer:{
host:'0.0.0.0',
port:8081,
// 跨域解决
proxy:{
'/api':{
target:"https://www.csdn.net/",
changeOrigin:true,
ws:true,
secure:false,
pathRewrite:{
'^/api':'/api'
}
}
}
}
}
配置完成后要重启本地服务器.
2. 使用实例
使用axios
发起网络数据请求, 首先要安装:
cnpm install axios --save
安装完成后, 在src
目录添加network
文件夹, 在其中新建request.js
, 封装网络数据请求:
import axios from 'axios'
export function request(config){
const instance = axios.create({
baseURL:'/api'
})
return instance(config)
}
因为完整的csdn
的API接口地址为:https://www.csdn.net/api/articles?type=more&category=home&shown_offset=1524276761019196&first_view=false
. 所以在baseURL:'/api'
.
3. 在使用数据的组件页面调用代码
经过封装的request.js
在需要数据请求的组件中就可以直接调用.示例代码如下:
<script>
import {onMounted, reactive} from 'vue'
import {request} from "@/network/request";
export default {
name: 'Home',
setup(){
const state=reactive({
result:null
})
onMounted(()=>{
request({
url:'/articles?type=more&category=home&shown_offset=1524276761019196&first_view=false'
}).then(res=>{
console.log(res);
})
})
return {state}
}
}
</script>
注意: vue3.0开始启用组合式API, 组件数据请求应该放置在生命周期函数onMounted
中完成.