Vue+axios+Flask+MongoDB前后分离跨域请求

vue

跨域请求访问事情

1、场景描述

1、前端使用Vue + Vue-router + Vant + axios

2、封装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

//引用axios

import 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

回到顶部