一、electron+axios
1、遇到的问题:在渲染进程中使用axios会出现跨域问题
2、解决办法:
1)修改渲染进程的html页面CSP规则,保留self同源,另外添加具体的接口服务地址
弊端:
- 1、修改CSP规则以允许特定的外部资源访问可能会降低应用的安全性,特别是当允许非同源的资源访问时,应用可能更容易受到跨站脚本攻击(XSS)和其他类型的安全威胁。
- 2、Electron的未来版本可能会对安全性进行进一步的增强或调整,因此依赖于当前CSP规则的配置可能会在未来的版本中失效或不再被支持
- 3、不同Electron版本或不同浏览器引擎对CSP规则的支持存在差异,另外Electron在不同的平台上运行(如Windows、macOS、Linux)等,需确保CSP规则都能支持和应用
2)使用electron代理发送请求,参考文章electron使用axios解决cors问题
缺点:这样的请求方式 在控制台是看不到请求的 调试非常不方便,无法处理复杂的请求,例如,上传文件需要传递FormData格式的数据,而Electron的IPC机制要求发送的数据必须能够被结构化克隆算法克隆(数据被序列化),例如函数、Symbol或循环引用的对象,以及某些类型的对象(File,Blob等)会导致请求报错:IpcRenderer.invoke Error: An object could not be cloned (使用ipcMain.handle发送不能被克隆)
使用: 创建一个http.js
import { ipcMain,dialog } from "electron";
import axios from "axios";
const BASE_URL = 'http://xx.xx'
const Headers = {Accept: "application/json, text/plain, */*"
}export const http = () => {ipcMain.handle("http-request", async (e, { url, method, data, params,headers}) => {const _url = BASE_URL + url;const _data = data?data:null const _params = params?params:null const _method = method;try {let response = null;if (_method === "POST") {response = await axios({method:_method,url: _url,data: _data,headers: Headers,});} else {response = await axios({method:_method,url: _url,params: _params,headers: Headers,});}return { data: response.data };} catch (err) {return { error: err.message };}});
};
在background.js中引入
import http from './http.js'
http()
在渲染进程中使用
//this.$electron是在main.js中绑定到了Vue.prototype上面
//const electron = window.require('electron')
//Vue.prototype.$electron = electronconst res = await this.$electron.ipcRenderer.invoke('http-request', {url: '/system/auth/login',method: 'POST',data: {password: "xxxx",username: "xxxx",}})
使用这种方式不会有跨域的问题,但是只能处理简单的数据请求,且不方便打印调试
3)使用fetch发送请求
是 ES6 引入的新的 API,现代浏览器基本都支持,但在一些旧版本浏览器中需要使用 polyfill 来实现兼容。
使用:创建一个http.js
class ApiClient {constructor(baseURL, options = {}) {this.baseURL = baseURL;this.defaultOptions = {timeout: 30000,credentials: 'include',...options};// 请求拦截器this.requestInterceptors = [];// 响应拦截器this.responseInterceptors = [];}/*** 核心请求方法*/async _fetch(url, options) {// 合并配置const mergedOptions = {...this.defaultOptions,...options,headers: {...this.defaultOptions.headers,...options.headers}};// 应用请求拦截器for (const interceptor of this.requestInterceptors) {await interceptor(mergedOptions);}// 设置超时const controller = new AbortController();const timeoutId = setTimeout(() => controller.abort(), mergedOptions.timeout);try {const fullUrl = this.baseURL ? `${this.baseURL}${url}` : url;const response = await fetch(fullUrl, {...mergedOptions,signal: controller.signal});clearTimeout(timeoutId);// 应用响应拦截器let processedResponse = response;for (const interceptor of this.responseInterceptors) {processedResponse = await interceptor(processedResponse);}if (!processedResponse.ok) {const errorData = await this._parseError(processedResponse);throw new HttpError(processedResponse.status,errorData.message || 'Request failed',errorData);}return this._parseResponse(processedResponse);} catch (error) {clearTimeout(timeoutId);if (error.name === 'AbortError') {throw new HttpError(408, 'Request timeout');}throw error;}}// 添加拦截器addRequestInterceptor(interceptor) {this.requestInterceptors.push(interceptor);}addResponseInterceptor(interceptor) {this.responseInterceptors.push(interceptor);}// 快捷方法get(url, options = {}) {return this._fetch(url, { ...options, method: 'GET' });}post(url, body, options = {}) {return this._fetch(url, {...options,method: 'POST',body: JSON.stringify(body),headers:{'Content-Type':'application/json'}});}put(url, body, options = {}) {return this._fetch(url, {...options,method: 'PUT',body: JSON.stringify(body)});}delete(url, options = {}) {return this._fetch(url, { ...options, method: 'DELETE' });}// 文件上传upload(url, formData, options = {}) {const headers = {...options.headers,};delete headers['Content-Type'];return this._fetch(url, {...options,method: 'POST',body: formData,headers});}// 解析响应async _parseResponse(response) {const contentType = response.headers.get('content-type') || '';if (contentType.includes('application/json')) {return response.json();}if (contentType.includes('text/')) {return response.text();}return response.blob();}// 解析错误async _parseError(response) {try {return await response.json();} catch {return { message: response.statusText };}}}const Http = new ApiClient(ELECTRON_CONFIG.AXIOS_URL);// 添加请求拦截器Http.addRequestInterceptor(async (options) => {//请求拦截添加token});// 添加响应拦截器Http.addResponseInterceptor(async (response) => {return response;});export default Http
在main.js中引入
import Http from '@/Http/http'
Vue.prototype.$Http = Http
发送请求
const res = await this.$Http.upload('xxx',data) if(res.code == 500){this.$message.error(res.msg)return}