由于浏览器同源策略的限制(同一主机不同端口之间),会产生客户端向服务端请求存在跨域的问题,如向服务端发送获取数据的请求,客户端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app">
<button @click="getUser">获取用户信息</button>
<ul>
<li v-for="(item,index) in users">{{item}}</li>
<li v-for="(item,index) in users">{{item.id}}</li>
<li v-for="(item,index) in users">{{item.name}}</li>
<li v-for="(item,index) in users">{{item.register_date}}</li>
</ul>
</div>
</body>
<script src="js/vue.js"></script>
<script src="js/axios.js"></script>
<script>
new Vue({
el: '#app',
data: {
apiDomain: 'http://localhost:8000/api/v1',
users: []
},
methods: {
getUser() {
let self = this
axios.get(`${this.apiDomain}/user/`).then(function (response) {
self.users = response.data.data
console.log(response)
}).catch(function (error) {
console.log(error)
})
}
}
});
</script>
</html>
服务端:
from rest_framework import views, serializers, response
from .. import models
class UserSerializer(serializers.ModelSerializer):
name = serializers.CharField(max_length=5, error_messages={'max_length': '字段太长!'})
register_date = serializers.DateTimeField(format='%Y-%m-%d %X')
class Meta:
model = models.User
fields = ('name', 'register_date', 'id')
class User(views.APIView):
def get(self, request):
qs = models.User.objects.all().first()
serializer = UserSerializer(qs, many=False)
return response.Response({
'status': 0,
'data': serializer.data
})
当点击获取数据的按钮后,报错:
这时候可以在Django中写中间件,通过修改 response的属性允许这个域的请求
来解决:
from django.utils.deprecation import MiddlewareMixin
class M1(MiddlewareMixin):
def process_response(self, request, response):
response['Access-Control-Allow-Origin'] = '*'
return response
记得需要在配置文件中配置这个中间件:
MIDDLEWARE = [
...
'app.middle.M1'
]
这个时候就可以成功获取数据:
再看下提交数据的请求:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app">
<button @click="getUser">获取用户信息</button>
<button @click="createUser">创建用户信息</button>
<ul>
<li v-for="(item,index) in users">{{item}}</li>
<li v-for="(item,index) in users">{{item.id}}</li>
<li v-for="(item,index) in users">{{item.name}}</li>
<li v-for="(item,index) in users">{{item.register_date}}</li>
</ul>
</div>
</body>
<script src="js/vue.js"></script>
<script src="js/axios.js"></script>
<script>
new Vue({
el: '#app',
data: {
apiDomain: 'http://localhost:8000/api/v1',
users: []
},
methods: {
getUser() {
let self = this
axios.get(`${this.apiDomain}/user/`).then(function (response) {
self.users = response.data.data
console.log(response)
}).catch(function (error) {
console.log(error)
})
},
createUser() {
let self = this
axios.post(`${this.apiDomain}/user/`, {"name": 'Thanlon'}).then(function (response) {
console.log(response)
}).catch(function (error) {
console.log(error)
})
}
}
});
</script>
</html>
发送POST请求提交数据的时候,客户端报错竟然也报跨域问题。根据报错提示,这是不允许请求头引起的,所以需要配置允许的请求头Access-Control-Allow-Headers:
并且服务端报错:
这是因为一般跨域会出现预检请求,浏览器会认为这是一次复杂的请求,会先发一个请求做预检。预检请求响应的状态是200的时候才会发真正的请求。所以,还需要在 中间件中设置允许的方法
:
from django.utils.deprecation import MiddlewareMixin
class M1(MiddlewareMixin):
def process_response(self, request, response):
# 允许请求的域
response['Access-Control-Allow-Origin'] = '*'
# 允许请求的请求头
response['Access-Control-Allow-Headers'] = '*'
# 允许请求的方法,适用*是允许所有,还可以指定。需要用都好隔开,例如'OPTIONS,GET,POST',实测发现这里不需要也是可以的
# response['Access-Control-Allow-Methods'] = 'OPTIONS'
return response