如题,记录告警平台从原来的layui升级到Vue,并实现Flask+Vue前后端分离,记录前后端三种解决跨域的方式(有点像茴香豆的四种写法?没事,技多不压身)

Flask解决跨域

不需要render_template了,只需要提供API给前端提供数据,需要解决跨域的问题,或者通过前端代理解决,或者通过Nginx代理解决(一共三种)

from flask import Flask, render_template

from flask_cors import *
"""flask-cors解决跨域问题的主角"""
from models import model_to_dict
from models import Alarm, AlarmGroup, db
from fake_data_generator import generate_fake_data
app = Flask(__name__)
CORS(app, resources={r'/*': {'origins': 'http://localhost:5173'}})
# CORS(app, resources={r'/*': {'origins': '*'}})
"""将导入的CORS应用,指定来源为任意,或者本地的5173"""

app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:123456@localhost:5432/yinyu'
db.init_app(app)

@app.route('/')
def hello_world():
    ## 测试数据库连接成功
    alarm = Alarm.query.first()
    print(alarm.name)
    return alarm.name
"""为了避免有时候容器没起,数据库没连上,这里做个测试,连上了,页面就会显示数据库中的一个名字"""

@app.route('/api/alarm',methods=['GET'])
def get_alarms():
    alarms = Alarm.query.all()
    alarms_list = [model_to_dict(a) for a in alarms]
    """query查到的是一个ORM对象,在model.py里面有model_to_dict的方案,在头部导入了"""
    return alarms_list

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
        generate_fake_data()
     """携带上下文,清空数据库,重新生成数据"""
    app.run()

Vue操作

通过axios模块,安装npm install axios,在src路径下创建axios.js

import axios from 'axios'

const instance = axios.create({
    baseURL: 'http://localhost:5000'
    //指定请求的基本地址,也就是后面的api会接在这个的后面的
  })

export default instance
//还有一些额外的配置可以添加,本次不深究

app.vue是Vue的程序入口文件,配置axios请求后端

<template>
  <div>
    <h1>{{ message }}</h1>
  </div>
</template>

<script>
import axios from "./axios"
//注意,这里需要引入上一步的axiox,同级目录

export default {
  data() {
    return {
      message: ''
    }
  },
  mounted() {
    //使用axios请求/api/alarm,也就是请求baseURL+/api/alarm
    axios.get('/api/alarm', {
      })

      .then(response => {
        console.log(response.data); // 打印响应数据
        this.message = response.data; // 将响应数据存储在 message 中
      })
      .catch(error => {
        console.log(error); // 打印错误信息
      })
  }
}
</script>

<style lang="scss" scoped>
.logo {
  width: 120px;
  height: 120px;
}

nav {
  padding: 10px;

  a {
    padding: 10px;
  }
}
</style>

Vue 代理解决跨域

vite.config.js是vite的配置文件,可以在这里配置一个代理,从而解决跨域问题

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({

  server: {
    //
    // proxy: {
    //   "^/api": {
    //     target: "http://localhost:5000",
    //     changeOrigin: true,
    //     rewrite: (path) => path.replace(/^\/api/, ""),
    //   },
    // },
    //以上被注释掉的部分就是有效内容,为了避免冲突,使用Flask即可。
  },
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

在经历过404(链接错了)、500(请求不到后端,本质还是链接错了),ERR_SSL_PROTOCOL_ERROR(AI补全补了个https,没注意到),和跨域错误后

image-20230712210636499

完事,收工!

Nginx解决跨域

server {
  listen 80;
  server_name api.example.com;

  location / {
    proxy_pass http://localhost:5000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # 上面的set_header就是解决跨域的配置
    
  }
}

server {
  listen 80;
  server_name app.example.com;

  location /api {
    rewrite ^/api/(.*) /$1 break; 
    proxy_pass http://api.example.com;
  }

  location / {
    root /var/www/app;
    try_files $uri $uri/ /index.html;
  }
}