vue前端解决跨域

79 阅读3分钟

配置代码

新建一个文件:vue.config.js
代码如下

const path = require('path');
function resolve(dir) {
    return path.join(__dirname, dir)
}
  
module.exports = {
    //打包时不生成.map后缀文件
    productionSourceMap: false,

    lintOnSave: false,
    // 基本路径
    publicPath: "./",
    // 输出文件目录
    outputDir: "dist",
    // 用于嵌套生成的静态资产(js,css,img,fonts)的目录。
    assetsDir: "./",

    // devServer: {
    //     // 项目运行时候的端口号
    //     port: 8088,
    // },
    devServer: {
      open: true,
      // host: 'localhost',
      port: 8080,
      https: false,
      //以上的ip和端口是我们本机的;下面为需要跨域的
      proxy: {//配置跨域
        '/api': {
          // target: 'http://192.168.0.80:8080',//这里后台的地址模拟的;应该填写你们真实的后台接口
          target: 'http://192.168.0.98:8080',
          // target: 'http://192.168.0.153:8080',
          // target: 'http://192.168.0.208:8080',
          ws: true,
          changOrigin: true,//允许跨域
          pathRewrite: {
            '^/api': '/'//请求的时候使用这个api就可以
          },
        //   logLevel: 'debug' // 用于检查代理的真实地址
        }
      }
    },
    /**
     * 别名映射文件路径
     */
    chainWebpack: (config) => {
        config.resolve.alias
            .set('@', resolve('src'))
            .set('assets', resolve('src/assets'))
            .set('components', resolve('src/components'))
            .set('views', resolve('src/views'))
            .set('utils', resolve('src/utils'))
            .set('store', resolve('src/store'))
            .set('plugins', resolve('src/plugins'))
    },
    configureWebpack: {
    }
};



重点代码

import path from 'path'
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  //服务器配置
  server: {
    host: '0.0.0.0',
    port: '8088', // 指定开发服务器端口。注意:如果端口已经被使用,Vite 会自动尝试下一个可用的端口
    strictPort: false, // 设为 true 时若端口已被占用则会直接退出,而不是尝试下一个可用端口。
    https: false,
    open: true, // 在开发服务器启动时自动在浏览器中打开应用程序
    //代理配置
    proxy: {
      '/api': {
        // target: 'http://192.168.0.80:8080',
        target:'',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')
      }
    }
  },

  plugins: [
    Vue(),
    AutoImport({
      // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
      imports: ['vue']
    })
  ]
})

封装post请求方法api.js文件

import axios from 'axios';
import { ElMessage } from 'element-plus';
import { getToken, removeToken } from '@/utils/token.js';
import Router from '@/router';
import { hideLoading } from '@/views/component/loading'
import qs from 'qs';

//请求拦截器
axios.interceptors.request.use(
  (config) => {
    config.headers['token'] = getToken();
    return config;
  },
  (err) => {
    closeLoading()
    ElMessage.error('系统错误,请求失败!');
  }
);

//响应拦截器
axios.interceptors.response.use(
  (data) => {
    closeLoading()
    if (data.headers.tokenstatus === 'tokenTimeout') {
      removeToken();
      ElMessage.error('登录信息已过期,请重新登录!');
      Router.push('/login').catch((err) => err);
      return data;
    }
    return data;
  },
  (err) => {
    closeLoading()
    switch (err.response.status) {
      case 401:
        removeToken();
        ElMessage.error(err.response.data.body.msg);
        Router.push('/login');
        break;
      default:
        ElMessage.error('系统错误,请求失败!');
        break;
    }
    if (!err.response.status) {
      closeLoading()
      return { data: err.response };
    }
  }
);

/**
 * axios请求的封装
 * axios默认请求类型为application/json
 */
axios.defaults.baseURL = '/api/';
// 允许跨域携带cookie信息
axios.defaults.withCredentials = true;
// 表示所有axios请求都是跨域请求,那么每次请求之前都会发送一个Options(预检)请求,用于询问后端是否允许本次请求。所以需要后端也进行相应的设置。
axios.defaults.crossDomain = true;

// post请求
export const postRequest = (url, params, isList = false) => {
  params = notNull(params);
  let transformRequest = [
    function (data) {
      let ret = '';
      for (let i in data) {
        ret += encodeURIComponent(i) + '=' + encodeURIComponent(data[i]) + '&';
      }
      return ret;
    },
  ];
  if (isList) {
    transformRequest = [
      function (data) {
        // 解决传递数组变成对象的问题
        return qs.stringify(data, { arrayFormat: 'indices', allowDots: true });
      },
    ];
  }
  return axios({
    method: 'post',
    url: url,
    data: params,
    //axios自带的数据操作方法,可以在请求前将数据格式化
    transformRequest: transformRequest,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
    },
  });
};

// get请求
export const getRequest = (url, params) => {
  return axios({
    method: 'get',
    url: url,
    params: params,
  });
};

// 后台返回流的请求
export const postStreamRequest = (url, params) => {
  return axios({
    method: 'post',
    url: url,
    params: params,
    responseType: 'arraybuffer',
  });
};

export const notNull = (data) => {
  for (let k1 in data) {
    if (data[k1] === null) {
      data[k1] = '';
      continue;
    }
    if (Object.prototype.toString.call(data[k1]) === '[object Object]') {
      notNull(data[k1]);
      continue;
    }
    if (Array.isArray(data[k1])) {
      for (let k2 in data[k1]) {
        if (
          Object.prototype.toString.call(data[k1][k2]) === '[object Object]'
        ) {
          notNull(data[k1][k2]);
        }
      }
      continue;
    }
  }
  return Object.assign({}, data);
};

function closeLoading(){
  try{
    hideLoading()
  }catch(e){

  }
}

main.js文件

import { createApp } from 'vue'
const app = createApp(App)

import App from './App.vue'
import router from './router'
import store from './store'
import common from './assets/css/common.css'
// 导入所有element-plus组件
import ElementPlus from 'element-plus'
// 导入element-plus 样式
import 'element-plus/dist/index.css'
// element-plus 语言默认为英文,在此导入中文包
import zhCn from 'element-plus/es/locale/lang/zh-cn'
// 导入所有element-plus的图标
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// 全局注册element-plus的图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

import './assets/css/cover-element-plus.less'
import { postRequest, getRequest } from '@/utils/http.js'
import { showLoading, hideLoading } from '@/views/component/loading'
import {downloadFile} from '@/utils/download.js'
// 注入全局方法
app.config.globalProperties.$getRequest = getRequest
app.config.globalProperties.$postRequest = postRequest
app.config.globalProperties.$showLoading = showLoading
app.config.globalProperties.$hideLoading = hideLoading
app.config.globalProperties.$downloadFile = downloadFile

//全局引入
import vue3Cron from 'jeeplus-cron'
import 'jeeplus-cron/lib/vue3Cron.css' // 引入样式

// 此处echarts配置为按需引入 echarts文档地址:https://echarts.apache.org/handbook/zh/basics/import
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core'
// 引入柱状图,折线图 图表,图表后缀都为 Chart
import { BarChart, LineChart, PieChart } from 'echarts/charts'
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,图例,工具栏,组件后缀都为 Component
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  LegendComponent,
  ToolboxComponent,
  PolarComponent
} from 'echarts/components'
// 标签自动布局,全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features'
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers'

 

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  LegendComponent,
  ToolboxComponent,
  PolarComponent,
  BarChart,
  LineChart,
  PieChart,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer
])

// 注入全局方法
app.config.globalProperties.$echarts = echarts

app
  .use(store)
  .use(router)
  .use(ElementPlus, {
    locale: zhCn
  })
  .use(vue3Cron)
  .mount('#app')
  //设置点击弹窗空白处不关闭
  app._context.components.ElDialog.props.closeOnClickModal.default = false

在实例中运用(直接写上接口名称就可以了)

如果不使用封装可以直接写成api/login/doLogin就可以了 api就是之前代理的地址http://198.168.0.98:8080

image.png