惊蛰的寓意是天气回暖、春雷始鸣,惊醒蛰伏于地下冬眠的昆虫,象征着自然界的生机勃勃和万物复苏
回顾
上一篇文章虽然做了简单的登录和登出,实际上是没有调接口
传统的web应用就是一个渲染页面,可以直接在里面进行http请求等等,而且是有域名的,后端也可以设置cros黑白名单。
但是electron如果在渲染进程操作是极为不安全的且会跨域的,所以请求方法都是放在主进程,渲染进程聚是一个纯渲染ui,请求以及桌面内部操作都是放到了主进程来实现
我们用上一篇文章的代码:electron-vue3-template进行增强调用请求,暂时用的apifox的mock接口
进入正题...
改造项目(主进程调用方式)
- 我们用最流行的aixos npm包
npm
npm install axios --save
- 在src/main/ 增加 http.ts 对axios进行简单拦截器封装和业务封装
ts
import axios from 'axios'
import { ipcMain } from 'electron'
const settings = require('electron-settings')
import log from 'electron-log'
export interface ApiResponse<T> {
success: boolean
errorCode: string
data: T
message: string
}
// 创建 Axios 实例
const axiosInstance = axios.create({
baseURL: 'https://m1.apifoxmock.com', // 这里可以改为你自己的api baseUrl
timeout: 30000,
headers: {
'Content-Type': 'application/json; charset=UTF-8'
}
// withCredentials: true
})
// 请求拦截器
axiosInstance.interceptors.request.use(
(config) => {
const token = settings.getSync('token')
// 在发送请求之前做些什么
// 例如可以在这里添加 token 到请求头中
// 登录在第一次是不需要的
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => {
// 处理请求错误
return Promise.reject(error)
}
)
// 响应拦截器
axiosInstance.interceptors.response.use(
(response) => {
if (response.status !== 200) {
log.error(response.headers, response.data.msg)
}
return response.data
},
(error) => {
// 处理超时错误
if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) {
log.error('请求超时:', error.config.url)
return Promise.reject({
success: false,
message: '请求超时,请稍后重试',
data: null
})
}
// 确保 error.response 存在
if (!error.response) {
log.error(error)
log.error('网络错误:', error.message)
return Promise.reject({
success: false,
message: '网络连接错误,请检查网络设置',
data: null
})
}
// 这里是业务上token过期或者鉴权失败等等,根据你业务代码来
if (error.response && error.response.status === 424) {
// 如果响应状态码为 424,移除 token,并且退出
settings.unsetSync('token')
ipcMain.emit('main-logout-success') // 主进程调用自己用emit
}
if (error.response.status === 504) {
log.info('error', '504 GATEWAY_TIMEOUT')
}
log.info('报错接口:', error.response.config.url)
log.info('报错接口错误:', error.response.data)
// 处理响应错误
return Promise.reject({
success: false,
message: error.message,
data: null
})
}
)
export default axiosInstance
- 我们对api接口进行统一管理,在src/下面增加apis文件夹
ts
// src/apis/index.ts
export const authApis = {
loginIn: '/m1/6017821-5706748-default/api/token' // apifox的mock接口
}
export const otherApis = {}
- 注意这里为了之后好引用改造下全局的tsconfig.node.json文件:
json
{
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*","src/apis"],
"compilerOptions": {
"composite": true,
"types": ["electron-vite/node"]
}
}
// 增加了"src/apis"
再改动一下全局的tsconfig.web.json文件
json
{
"extends": "@electron-toolkit/tsconfig/tsconfig.web.json",
"include": [
"src/renderer/src/env.d.ts",
"src/renderer/src/**/*",
"src/renderer/src/**/*.vue",
"src/preload/*.d.ts",
"src/apis/*" // 增加这个
],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@renderer/*": [
"src/renderer/src/*"
],
"@apis/*": [
"src/apis/*" // 增加这个
],
}
}
}
// 增加@apis/* 以便后续在渲染进程用
- 我们要改造我们的登录方法src/main/index.ts
ts
import axiosInstance from './http'
import { authApis } from '../apis'
// 改造我们的登录方法
ipcMain.handle('loginIn', async (event, params) => {
log.info('login----params', params)
try {
const response: any = await axiosInstance.post(`${authApis.loginIn}`, params)
if (response.success) {
log.info('登录成功---返回', response)
settings.setSync('token', response.data.access_token) // 存到应用本地数据库
ipcMain.emit('main-login-success') // 通知登录成功了
} else {
log.info('登录失败---返回', response)
return { message: '登录失败', success: false, data: null }
}
return response // 返回请求数据
} catch (error: any) {
log.error('Uncaught Exception:', error)
return { message: error.message, success: false, data: null } // 返回错误信息
}
})
这时候重启项目进入登录界面:
账号用:admin 密码: 123 (才会正常登录)
上面在主进程已经可以正常调用了,那我们在渲染进程怎么调用请求呢。 不可能我们在渲染调用一个请求就要写很多ipcMain.handle 之类的吧
那我们接下来进行渲染进程的改造...
改造项目(渲染进程调用)
我们受ipcMain.handle的启发,其实我们可以重复封装一些方法给到渲染进程的
- 改动一下electron.vite.config.ts
json
alias: {
'@renderer': resolve('src/renderer/src'),
'@apis': resolve('src/apis') // 增加这个
}
- 在src/main/index.ts setIpcHandlersForAxios函数里面增加2个通用型方法
ts
// 统一的get-data
ipcMain.handle("get-data", async (event, url, params) => {
log.info("get-data", url, params)
try {
const response: any = await axiosInstance.get(url, { params })
if (!response.success) {
log.error("请求失败:url", `msg:${response.message}`, `errorCode:${response.errorCode}`, url)
} else {
log.info("get-data-success:", url)
}
return response // 返回请求数据
} catch (error: any) {
log.error("Uncaught Exception:url", error.message, url)
return { success: false, message: error.message, error: error.message }
}
})
// 统一的post-data方法
ipcMain.handle("post-data", async (event, url, params) => {
log.info("post-data", url, params)
try {
const response: any = await axiosInstance.post(url, params)
if (!response.success) {
log.error("请求失败", `msg:${response.message}`, `errorCode:${response.errorCode}`, url)
} else {
log.info("post-data-success:", url)
}
return response // 返回请求数据
} catch (error: any) {
log.error("Uncaught Exception:url", error.message, url)
return { success: false, message: error.message, error: error.message } // 返回错误信息
}
})
我们2个普通的get和post封装好了,我们可以在渲染进程用了
- 在renderder下面增加service文件夹且添加index.ts
ts
const invokeData = window.electron.ipcRenderer.invoke
import { otherApis } from '@apis/index'
export async function fetchMockList() {
return invokeData('get-data', otherApis.getList)
}
- 改造我们之前的views/home/index.vue页面发起请求
vue
<template>
<div class="home">
接口返回数据:
<div>
<div v-if="data && data.length">
<div v-for="item in data" :key="item.id" class="item">
<div>{{ item.text }}</div>
</div>
</div>
<div v-else>
<p>没有数据可显示。</p>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { fetchMockList } from '@renderer/service/index'
let data = ref([])
onMounted(async () => {
await fetchList()
})
const fetchList = async () => {
const res = await fetchMockList()
console.info('res', res)
if (res.success) {
data.value = res.data
}
}
</script>
<style scoped>
.home {
height: 100%;
width: 100%;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
}
</style>
最终效果如下:
上面完整的主进程调用http请求以及渲染进程调用已经基本实现了
希望对你有所帮助! 后续会更新更多实战项目的技术点...
最后附上源码地址electron-vue3-template