package.json
"scripts": {
"build": "nuxt build --dotenv .env.prod",
"build:dev": "nuxt build --dotenv .env.dev",
"postbuild": "mv -f .output ./dist/.output", //支持自定义文件名
"dev": "nuxt dev --dotenv .env.dev",
"dev:prod": "nuxt dev --dotenv .env.prod",
}
.env.dev
VITE_BASE_PC_URL=http://pc.dev.com/api
VITE_BASE_MOBILE_URL=http://m.dev.com/api
VITE_API_KEY=675f3e7464bdfxxx
VITE_API_IV=2fd454e95cde8xxx
.env.prod
VITE_BASE_PC_URL=http://pc.prod.com/api
VITE_BASE_MOBILE_URL=http://m.prod.com/api
VITE_API_KEY=675f3e7464bdfxxx
VITE_API_IV=2fd454e95cde8xxx
nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
// 私有环境变量,仅服务端可访问
apiKey: process.env.VITE_API_KEY,
apiIV: process.env.VITE_API_IV,
pcURL: process.env.VITE_BASE_PC_URL,
mobileURL: process.env.VITE_BASE_MOBILE_URL,
}
})
plugins/axiosPlugin.ts(服务端/客户端使用runtimeConfig.pcURL)
import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, AxiosRequestHeaders } from 'axios';
import CryptoJS from 'crypto-js';
import { defineNuxtPlugin } from '#app';
// 加密函数
function encrypt(plainText: string, key: string, iv: string): string {
const keyHex = CryptoJS.enc.Utf8.parse(key);
const ivHex = CryptoJS.enc.Utf8.parse(iv);
const encrypted = CryptoJS.AES.encrypt(plainText, keyHex, {
iv: ivHex,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
export default defineNuxtPlugin(() => {
const runtimeConfig = useRuntimeConfig();
const deviceType = useDeviceType();
const baseURL = deviceType?.type.value === 'pc' ? (runtimeConfig?.pcURL || process.env.VITE_BASE_PC_URL) : (runtimeConfig?.mobileURL || process.env.VITE_BASE_MOBILE_URL);
const axiosInstance: AxiosInstance = axios.create({
baseURL: baseURL,
timeout: 30000, // 请求超时时间
});
let customHeadersConfig: Record<string, string> = {};
// 请求拦截器
axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
if (!config.headers) {
config.headers = {} as AxiosRequestHeaders;
}
config.headers['Content-Type'] = 'application/json;charset=UTF-8';
const plainText = String(new Date().getTime());
const apiKey = (runtimeConfig.apiKey || process.env.VITE_API_KEY);
const apiIV = (runtimeConfig.apiIV || process.env.VITE_API_IV);
// 检查环境变量是否定义
if (!apiKey || !apiIV) {
throw new Error('API 密钥或 IV 未定义');
}
const encryptedText = encrypt(plainText, apiKey, apiIV);
config.headers['Token'] = encryptedText;
for (let key in customHeadersConfig) {
// config.headers[key] = customHeadersConfig[key];
if (customHeadersConfig[key] === '') {
delete config.headers[key];
} else {
config.headers[key] = customHeadersConfig[key];
}
}
return config;
},
(error) => {
console.error('请求错误:', error.message || '未知错误');
return Promise.reject(error);
}
);
// 响应拦截器
axiosInstance.interceptors.response.use(
(response: AxiosResponse) => response.data,
(error) => {
if (error.response) {
console.log(`错误信息: ${error.response?.data?.message}`)
// switch (error.response.status) {
// case 400:
// console.log('未授权,请访问最新');
// break;
// case 401:
// console.log('未授权,请登录');
// break;
// case 404:
// console.log('请求资源不存在');
// break;
// case 500:
// console.log('服务器内部错误');
// break;
// default:
// console.log(`未知错误: ${error.response.status}`);
// break;
// }
} else {
console.log(`网络错误或其他错误: ${error}`);
}
return Promise.reject(error);
}
);
// 提取请求类型检查逻辑
function handleRequestType(url: string, params: any, type: string, customConfig?: {}) {
customHeadersConfig = customConfig || {};
if (type.toUpperCase() === 'GET') {
return axiosInstance.get(url, { params, ...customConfig });
} else if (type.toUpperCase() === 'POST') {
return axiosInstance.post(url, params, customConfig);
} else {
throw new Error('不支持的请求类型');
}
}
return {
provide: {
customRequest: (url = '', params = {}, type = 'POST', customConfig?: {}) => {
return handleRequestType(url, params, type, customConfig);
},
apiAxios: axiosInstance
}
}
});