Vue+axios+Flask+MongoDB前后分离跨域请求
跨域请求访问事情
1、场景描述
1、前端使用Vue + Vue-router + Vant + axios2、封装axios 请求,请求url: http://localhost:8080
3、后端使用Python-Flask 访问API: http://localhost:5000
4、数据库为:MongoDB
5、以上两上URL端口不相同,即为跨域请求
2、使用技术
2.1前端使用Vue
2.1.1 axios封装--请求API
/*** 用于封装请求的方法和url值;
* 2019-11-21
*/
const CONTACT_API = {
//获取联系人列表
getContactList: {
method: 'get',
url: '/contactList'
},
//新建联系人 form-data
newContactForm: {
method: 'post',
url: '/contact/new/form'
},
//新建联系人 application/json
newContactJson: {
method: 'post',
url: '/contact/new/json'
},
editContact: {
method: 'put',
url: '/contact/edit'
},
deleteContact: {
method: 'delete',
url: '/contact'
}
}
export default CONTACT_API
2.1.2 axios封装--请求Http
//引用axiosimport axios from 'axios'
//引入封装请求的API
import service from './contactApi'
import {Toast} from 'vant'
// service 循环遍历输出不同的请求方法
//创建请求实例
let instance = axios.create({
baseURL: 'http://localhost:5000/',
//contentType: "text/html;charset=utf8",
//dataType: "json",
timeout: 1000
})
//声明请求的HTTP对象;
const Http = {}; //包裹请求方法的容器
//请求格式或参数的统一
for(let key in service)
{
let api = service[key];
Http[key] = async function(
params, //请求参数get,url; post,patch,put(data)
isFormData = false, //是否form-data请求
config = {}
) {
//let url = api.url
let newParams = {}
if(params && isFormData){
newParams = new FormData()
for(let i in params){
newParams.append(i,params[i])
}
}else {
newParams = params
}
console.log('newParams....',newParams)
//不同请求判断
let response = {}; //请求响影的值;
if(api.method ==='post' ||api.method ==='put' ||api.method =='patch'){
try{
console.log('config',config)
response = await instance[api.method](api.url,newParams,config)
}catch(err){
response = err
}
}else if (api.method ==='delete' || api.method ==='get') {
config.params = newParams
try{
//instance[api.method] ---这一部分是获取Hanson名;
//(api.url,config) 为函数体,其中第1上参数为url,第二个参数为传递的params参数;
response = await instance[api.method](api.url,config)
}catch(err){
console.log(err)
}
}
return response
} // end function
}
//请求拦截器
//config 为请求的信息,封装有表头信息;
instance.interceptors.request.use(config=>{
console.log('request...',config)
Toast.loading({
mask: false,
duration: 0,
forbidClick: true, //禁止点击
message: '加载中.....'
})
//发起请求前
return config
}, ()=>{
Toast.clear()
Toast('请求错误,请稍后重试')
})
//请求响应的结果
//res为请求响应的结果;
instance.interceptors.response.use(res=>{
console.log('response....',res)
console.log('response-data',res.data)
if(res.status === 200)
{
Toast.clear()
return res.data
}
else
{
Toast('请求错误,请稍后重试')
}
},()=>{
Toast.clear()
Toast('请求错误,请稍后重试')
})
export default Http
2.1.3 Vue--contactlist组件
<template><div>
<van-contact-list
:list="list"
@add="onAdd"
@edit="onEdit"
@select="onSelect"
/>
<!-- 联系人编辑 -->
<van-popup v-model="showEdit" position="bottom">
<van-contact-edit
:contact-info="editingContact"
:is-edit="isEdit"
@save="onSave"
@delete="onDelete"
/>
</van-popup>
</div>
</template>
<script>
import axios from "axios";
import { ContactList, Toast, ContactEdit, Popup } from "vant";
export default {
data() {
return {
list: [{
name: '张三',
tel: '13800000000',
id: 0
}],
instance: null,
showEdit: false,
editingContact: {},
isEdit: false
}
},
components: {
[ContactList.name]: ContactList,
[ContactEdit.name]: ContactEdit,
[Popup.name]: Popup
},
methods: {
//获取列表信息
async getList() {
let res = await this.$Http.getContactList()
console.log('getList....',res)
this.list = res
},
//添加联系人;
onAdd() {
this.showEdit = true
this.isEdit = false
},
//编辑联系人
onEdit(info) {
this.showEdit = true
this.isEdit = true
this.editingContact = info
},
onSelect() {
},
async onSave(info) {
if(this.isEdit){
let res = this.$Http.editContact(info)
console.log('edit....',res);
this.showEdit = false
this.getList()
}else{
try{
this.$Http.newContactJson(info)
Toast('新建成功')
this.showEdit = false
this.getList()
}catch(err){
console.log(err)
}
}
},
//删除记录
async onDelete(info) {
try
{
let res = await this.$Http.deleteContact(info)
Toast('删除成功')
this.showEdit = false
this.getList()
}
catch(err)
{
console.log(err)
}
}
},
//Vue生命周期函数
created() {
this.getList()
}
}
</script>
<style scoped>
.van-contact-list__add{
z-index: 0;
}
.van-popup {
height: 100%;
}
</style>
2.1.4 请求Http的挂载
==== main.js =====import Vue from 'vue'
import App from './App.vue'
import router from './router'
import Http from './service/http.js'
Vue.config.productionTip = false
//挂载http请求实例;
Vue.prototype.$Http = Http
new Vue({
router,
render: h => h(App)
}).$mount('#app')
2.2 后端使用Flask-MongoDB
2.2.1 查询
from flask import render_template,Response,json,make_response
from app.model import Contactlist
from . import vueapi
#查询记录
@vueapi.route('/contactList')
def get():
contacts = Contactlist.objects.filter()
list = []
cons = {
'id': 0,
'name': '',
'tel': ''
}
print(contacts[0].id)
for contact in contacts:
cons = {
'id': str(contact.id),
'name': contact.name,
'tel': contact.tel
}
list.append(cons)
print(str(contact.id) + ' ' + contact.name + ' ' + contact.tel)
res = make_response(json.dumps(list))
res.headers['Access-Control-Allow-Origin'] = '*'
return res
2.2.2 新增
#保存记录;@vueapi.route('/contact/new/json', methods=["POST"])
def save_data():
#获取参数信息;
data = eval(request.data.decode('utf-8'))
name = data.get('name')
tel = data.get('tel')
print(name+'...'+ tel)
#获取ID
count = Contactlist.objects.filter().count()+1
#实例化对象;
contact = Contactlist(id=count,name= name,tel=tel)
contact.save()
contacts = [{
'name': name,
'tel': tel
},]
#以下为解决跨域请求
res = make_response(json.dumps(contacts))
res.headers['Access-Control-Allow-Origin'] = '*'
res.headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS, DELETE'
res.headers['Access-Control-Allow-Credentials'] = 'true'
return res
2.2.3 修改
#更新记录@vueapi.route('/contact/edit',methods=['PUT'])
def update_data():
#获取参数值
data = eval(request.data.decode('utf-8'))
id = data.get('id')
name = data.get('name')
tel = data.get('tel')
#根据参数获取记录
contact = Contactlist.objects.get_or_404(id=id)
#修改查询出记录的内容;
contact.id = id
contact.name = name
contact.tel = tel
#保存记录
contact.save()
res = make_response('OK')
res.headers['Access-Control-Allow-Origin'] = '*'
res.headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS, DELETE'
res.headers['Access-Control-Allow-Credentials'] = 'true'
return res
2.2.4 删除
#删除记录@vueapi.route('/contact', methods=['delete'])
def delete_data():
id = request.args['id']
contact = Contactlist.objects.get_or_404(id = id)
if contact:
contact.delete()
res = make_response("OK")
res.headers['Access-Control-Allow-Origin'] = '*'
res.headers['Access-Control-Allow-Credentials'] = 'true'
return res
2.3 数据库MongoDB
2.3.1 配置文件
config.py
MONGODB_SETTINGS ={
'db': 'api_list',
'host': '127.0.0.1',
'port': 27017
}
2.3.2 数据模型
from app import db
class Contactlist(db.Document):
id = db.IntField(primary_key=True)
name = db.StringField()
tel = db.StringField()
meta = {
'collection': 'contacts',
'strict': False
}
def __repr__(self):
return '<Contactlist %r>' % self.name
3、跨域请求问题点
3.1 安装flask_cors
pip install flask_cors
3.2 flask_cors引用和注册
from flask import Flask
from flask_cors import *
from flask_mongoengine import MongoEngine
db = MongoEngine()
def create_app():
app = Flask(__name__)
app.config.from_object('config')
db.init_app(app)
#蓝图注册
from app.vueapi import vueapi as api_blueprint
app.register_blueprint(api_blueprint, url_prfix="/vueapi")
CORS(app, supports_credentials=True)
return app
3.2最终解决方案为:
需要在flask数据访问函数中增加response的表头信息:from flask import render_template,Response,json,make_response
res = make_response(json.dumps(list))
res.headers['Access-Control-Allow-Origin'] = '*'
下面这行很重要,否则会报上面的错误信息
4、最终结果:
以上是 Vue+axios+Flask+MongoDB前后分离跨域请求 的全部内容, 来源链接: utcz.com/z/376849.html