求助,如何解决vite.config.js代理配置失效问题?

新手上路,请多包涵

如何解决vite.config.js代理配置失效问题?
问题描述:一个前后端分离项目,前端为vue3+vite5+uniapp项目,
后端接口为http://47.93.153.78:8080/code,微信小程序中可以访问的到,但是H5中会显示跨域问题
Access to XMLHttpRequest at 'http://47.93.153.78:8080/code' from origin 'http://localhost:7001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
然后我这边去做代理配置, 其中proxy替换VITE_APP_BASE_API (/dev-api) 没有生效,找了半天没找到原因,求助大佬帮忙看一下


import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { loadEnv } from 'vite'
import path from 'node:path'
import UnoCSS from 'unocss/vite'
import dayjs from 'dayjs'
import svgLoader from 'vite-svg-loader'
// 打包后,会在根目录下生成一个 stats.html文件
import { visualizer } from 'rollup-plugin-visualizer'
// 通过监听文件修改,自动重启 vite 服务  最常用的场景就是监听 vite.config.js 和 .env.development 文件,修改 vite 配置文件和环境配置文件,是需要重启 vite 才会生效
import ViteRestart from 'vite-plugin-restart'
import AutoImport from 'unplugin-auto-import/vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import viteCompression from 'vite-plugin-compression'
// import ViteImagemin from 'vite-plugin-imagemin'
import autoprefixer from 'autoprefixer'
import UniPages from '@uni-helper/vite-plugin-uni-pages'
import UniLayouts from '@uni-helper/vite-plugin-uni-layouts'

// 自定义插件方法
const htmlPlugin = () => {
    return {
        name: 'html-transform',
        transFormIndexHtml(html) {
            return html.replace('%BUILD_DATE%', dayjs().format(''))
        },
    }
}

// unplugin-vue-components uniapp 不支持,uniapp 使用easycom的方式自动引入组件,不需要这个vite插件

export default ({ mode }) => {
    // mode区分生产环境还是开发环境
    // process.cwd() 获取当前文件的目录和地址
    // loadEnv 返回当前环境env文件中额外定义的变量

    const env = loadEnv(mode, path.resolve(process.cwd()))
    console.log(env)

    return defineConfig({
        plugins: [
            UniPages({
                exclude: ['**/components/**/**.*'],
                routeBlockLang: 'json5', // 虽然设了默认值,但是vue文件还是要加上 lang="json5", 这样才能很好地格式化
                homePage: 'pages/home-page/index',
                subPackages: ['src/pages-sub'], // 这是个数组,可以写多个
            }),
            UniLayouts(),
            // UniXXX 需要在 Uni 之前引入
            uni(),
            // 在 Vite 驱动的 uni-app 上使用基于文件的路由系统。
            UnoCSS(),
            htmlPlugin(),
            svgLoader(),
            // 打包分析插件 打包后,会在根目录下生成一个 stats.html文件
            visualizer(),
            ViteRestart({
                // 修改vite.config.ts 不用手动重启vite就能生效
                restart: ['vite.config.ts'],
            }),
            // vue3等插件hooks自动引入
            // 支持vue, vue-router, vue-i18n, @vueuse/head, @vueuse/core等自动引入
            AutoImport({
                imports: ['vue'],
                // 可以选择auto-import.d.ts生成的位置,使用ts建议设置为src/auto-import.d.ts
                dts: 'src/auto-import.d.ts',
            }),
            // 在使用setup语法糖的时候没办法直接为组件定义name,需要使用两个script标签来完成
            // 使用vite-plugin-vue-setup-extend
            // <script lang="ts" setup name="自定义name">
            VueSetupExtend(),
            createSvgIconsPlugin({
                // 指定svg图标 保存的文件夹路径,
                iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
                // 指定symbolId格式
                symbolId: 'icon-[dir]-[name]',
            }),
            // 会多出一些.gz文件,如xxx.js.gz,这里默认是不会删除xxx.js文件的,如果想删除也可以增加配置
            // vite-plugin-compression是一个基于Vite的插件,用于gzip或Brotli压缩你的资源,从而减少页面的加载时间和网络带宽,提高用户访问速度和体验。
            viteCompression(),
        ],

        css: {
            postcss: {
                plugins: [
                    // 前端开发中,为兼容所有浏览器,部分CSS属性需要加上不同的浏览器前缀
                    autoprefixer({
                        // 指定目标浏览器
                        overrideBrowserslist: ['> 1%', 'last 2 versions'],
                    }),
                ],
            },
        },

        resolve: {
            // 配置路径别名
            alias: {
                '@': path.join(process.cwd(), './src'),
            },
        },

        server: {
            // host: '0.0.0.0',
            // hmr: true,
            port: 7001,
            cors: true,
            open: true,
            // 自定义代理规则
            proxy: {
                [env.VITE_APP_BASE_API]: {
                    target: 'http://47.93.153.78:8080', // 目标服务器的URL
                    changeOrigin: true,
                    rewrite: (path) => {
                        console.log('path-------------------------------------', path)
                        return path.replace(new RegExp(`^${env.VITE_APP_BASE_API}`), '')
                    },
                    bypass(req, res, options: any) {
                        const proxyURL = options.target + options.rewrite(req.url)
                        console.log('proxyURL', proxyURL)
                        req.headers['x-req-proxyURL'] = proxyURL // 设置未生效
                        res.setHeader('x-req-proxyURL', proxyURL) // 设置响应头可以看到
                    },
                },
            },
        },

        build: {
            // 处理清除console的插件
            minify: 'terser',
            terserOptions: {
                compress: {
                    drop_console: env.VITE_DELETE_CONSOLE === 'true',
                    drop_debugger: env.VITE_DELETE_CONSOLE === 'true',
                },
            },
        },
    })
}

这部分是env的配置

# 变量必须以VITE_为前缀才能暴露给外部获取
NODE_ENV = 'development'

VITE_SERVER_BASEURL = 'http://47.93.153.78:8080'
VITE_APP_BASE_API = '/dev-api'


# 是否去除console 和 debugger
VITE_DELETE_CONSOLE = false


这部分是request配置
import { useUserStore } from '@/store'
import type { UserInfo } from '@/typings'

// console.log('useUserStore:', useUserStore)

type Data<T> = {
    code: number
    msg: string
    data: T
}

// 请求基地址
export const baseUrl = import.meta.env.VITE_SERVER_BASEURL
export const baseUrlCors = import.meta.env.VITE_APP_BASE_API

// 拦截器配置
const httpInterceptor = {
    // 拦截器触发
    invoke(options: UniApp.RequestOptions) {
        const headers = options?.headers || {}
        const params = options?.params || {}
        // 1. 非http开头的请求地址需要拼接地址
        if (!options.url?.startsWith('http')) {
            options.url = baseUrl + baseUrlCors + options.url
        }

        // 携带参数
        if (Object.keys(params).length) {
            let carryParams = '?'
            Object.keys(params).forEach((item, index) => {
                carryParams += `&${item}=${params[item]}`
            })
            options.url += carryParams
        }
        // 2. 请求超时
        options.timeout = 10000 // 10s

        // 3. 添加小程序请求头标识
        options.header = {
            platform: 'mp-weixin', // 可选值与uniapp定义的平台一致, 告诉后台来源
            ...options.header,
        }

        // 4. 添加token请求头标识
        const userStore = useUserStore()
        const token = userStore.token
        if (token) {
            options.header.Authorization = `Bearer ${token}`
        }

        if (typeof headers.isToken === 'boolean' && !headers?.isToken) {
            delete options.header.Authorization
        }
    },
}

// 拦截request请求
uni.addInterceptor('request', httpInterceptor)

// 拦截uploadFile文件上传
uni.addInterceptor('uploadFile', httpInterceptor)

const http = <T>(options: UniApp.RequestOptions) => {
    // 返回Promise对象
    return new Promise<Data<T>>((resolve, reject) => {
        uni.request({
            ...options,
            // 响应成功
            success(res) {
                if ((res.data as Data<T>).code > 200 && res.statusCode === 200) {
                    uni.showToast({
                        icon: 'none',
                        title: (res.data as Data<T>).msg || '请求错误',
                    })
                    reject(res)
                }
                // 状态码 2xx 参考axios的设计
                else if (res.statusCode >= 200 && res.statusCode < 300) {
                    // 2.1 提取核心数据res.data
                    resolve(res.data as Data<T>)
                } else if (res.statusCode === 401) {
                    // 401错误 -> 清理用户信息, 跳转到登录页
                    const userStore = useUserStore()
                    userStore.logout()
                    uni.navigateTo({
                        url: '/pages/login/login',
                    })
                    setTimeout(() => {
                        uni.showToast({
                            icon: 'none',
                            title: '登陆过期',
                        })
                    })
                    reject(res)
                } else {
                    // 其他状态码 -> 根据后端错误信息轻提示
                    uni.showToast({
                        icon: 'none',
                        title: (res.data as Data<T>).msg || '请求错误',
                    })
                    reject(res)
                }
            },

            // 响应失败
            fail(err) {
                uni.showToast({
                    icon: 'none',
                    title: '网络错误, 换个网络试试',
                })

                reject(err)
            },
        })
    })
}

export default http


阅读 1k
1 个回答

request请求 H5的时候 不要添加baseUrl
代理配置代理的是本地请求,你添加了baseUrl就不会被本地服务代理了

// 请求基地址
export const baseUrl = import.meta.env.VITE_SERVER_BASEURL  // H5的时候 赋值为''
export const baseUrlCors = import.meta.env.VITE_APP_BASE_API
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏