优化检测URL是否有效方法,使其更贴近浏览器访问效果,以及当HEAD请求后收到403响应时,再用GET请求一次(也许Web服务器禁止了HEAD请求)。
This commit is contained in:
parent
51087027c8
commit
85036de5c3
@ -216,7 +216,7 @@ export interface TagResolutionConfig {
|
|||||||
/**
|
/**
|
||||||
* 缩放比例
|
* 缩放比例
|
||||||
*/
|
*/
|
||||||
Percentage: number;
|
Percentage: string | number;
|
||||||
/**
|
/**
|
||||||
* 特殊页面
|
* 特殊页面
|
||||||
*/
|
*/
|
||||||
@ -234,7 +234,7 @@ export interface SpecialPUrlItem {
|
|||||||
/**
|
/**
|
||||||
* 特殊页面缩放比例
|
* 特殊页面缩放比例
|
||||||
*/
|
*/
|
||||||
SPPer: number;
|
SPPer: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
63
src/main.ts
63
src/main.ts
@ -5,6 +5,8 @@ import * as http from 'http';
|
|||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
|
|
||||||
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
// Ensure only one instance is running
|
// Ensure only one instance is running
|
||||||
const gotTheLock = app.requestSingleInstanceLock();
|
const gotTheLock = app.requestSingleInstanceLock();
|
||||||
if (!gotTheLock) {
|
if (!gotTheLock) {
|
||||||
@ -32,34 +34,64 @@ ipcMain.handle('get-primary-display', () => screen.getPrimaryDisplay());
|
|||||||
// Check if the URL is available
|
// Check if the URL is available
|
||||||
ipcMain.handle('check-url-available', async (event, rawUrl: string) => {
|
ipcMain.handle('check-url-available', async (event, rawUrl: string) => {
|
||||||
try {
|
try {
|
||||||
const url = new URL(rawUrl);
|
const url: URL = new URL(rawUrl);
|
||||||
const lib = url.protocol === 'https:' ? https : http;
|
const lib = url.protocol === 'https:' ? https : http;
|
||||||
|
|
||||||
return await new Promise((resolve) => {
|
return await new Promise((resolve) => {
|
||||||
const req = lib.request(
|
// 先用HEAD请求,如果遇到403,则再用GET请求再试一次(部分服务器可能禁止HEAD请求)。
|
||||||
{
|
const requestOptions: http.RequestOptions | https.RequestOptions = {
|
||||||
method: 'HEAD',
|
|
||||||
hostname: url.hostname,
|
hostname: url.hostname,
|
||||||
port: url.port || undefined,
|
port: url.port || undefined,
|
||||||
path: url.pathname + url.search,
|
path: url.pathname + url.search,
|
||||||
|
headers: {
|
||||||
|
'Accept': '*/*',
|
||||||
|
'Accept-Encoding': 'gzip, deflate, br',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const headReq = lib.request(
|
||||||
|
{
|
||||||
|
method: 'HEAD',
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
|
...requestOptions
|
||||||
},
|
},
|
||||||
(res) => {
|
(res) => {
|
||||||
resolve({ ok: true, status: res.statusCode })
|
console.log('check-url-available HEAD', url.toString(), res.statusCode, res.statusMessage);
|
||||||
req.destroy()
|
if (res.statusCode === 403) {
|
||||||
|
headReq.destroy()
|
||||||
|
const getReq = lib.get({
|
||||||
|
method: 'GET',
|
||||||
|
...requestOptions
|
||||||
|
}, (res) => {
|
||||||
|
console.log('check-url-available GET', url.toString(), res.statusCode, res.statusMessage);
|
||||||
|
resolve({ ok: true, status: res.statusCode, message: res.statusMessage });
|
||||||
|
getReq.destroy()
|
||||||
|
});
|
||||||
|
getReq.on('error', (err) => {
|
||||||
|
resolve({ ok: false, error: err.message });
|
||||||
|
});
|
||||||
|
getReq.on('timeout', () => {
|
||||||
|
resolve({ ok: false, error: 'Timeout' });
|
||||||
|
getReq.destroy();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve({ ok: true, status: res.statusCode, message: res.statusMessage });
|
||||||
|
headReq.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
req.on('error', (err) => {
|
headReq.on('error', (err) => {
|
||||||
resolve({ ok: false, error: err.message })
|
resolve({ ok: false, error: err.message });
|
||||||
});
|
});
|
||||||
|
|
||||||
req.on('timeout', () => {
|
headReq.on('timeout', () => {
|
||||||
req.destroy()
|
resolve({ ok: false, error: 'Timeout' });
|
||||||
resolve({ ok: false, error: 'Timeout' })
|
headReq.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
req.end();
|
headReq.end();
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { ok: false, error: 'Invalid URL' };
|
return { ok: false, error: 'Invalid URL' };
|
||||||
@ -141,7 +173,9 @@ const createWindow = () => {
|
|||||||
|
|
||||||
win.webContents.on('did-attach-webview', (event, webContents) => {
|
win.webContents.on('did-attach-webview', (event, webContents) => {
|
||||||
webContents.setWindowOpenHandler((details) => {
|
webContents.setWindowOpenHandler((details) => {
|
||||||
|
if (isDevelopment) {
|
||||||
console.log('webview-new-window', webContents, details);
|
console.log('webview-new-window', webContents, details);
|
||||||
|
}
|
||||||
win.webContents.send('webview-new-window', webContents.id, details.url);
|
win.webContents.send('webview-new-window', webContents.id, details.url);
|
||||||
return { action: 'deny' };
|
return { action: 'deny' };
|
||||||
});
|
});
|
||||||
@ -172,6 +206,9 @@ const createWindow = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
globalShortcut.register("CommandOrControl+Shift+I", handleDevTools);
|
globalShortcut.register("CommandOrControl+Shift+I", handleDevTools);
|
||||||
|
if (isDevelopment) {
|
||||||
|
win.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
// and load the login.html of the app.
|
// and load the login.html of the app.
|
||||||
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
@ -185,7 +222,7 @@ const createWindow = () => {
|
|||||||
{ label: '显示窗口', click: () => win.show() },
|
{ label: '显示窗口', click: () => win.show() },
|
||||||
{ label: '退出程序', click: () => app.exit() }
|
{ label: '退出程序', click: () => app.exit() }
|
||||||
]);
|
]);
|
||||||
const iconPath = process.env.NODE_ENV === 'development' ? path.join(__dirname, '../../assets/tray.png') : path.join(process.resourcesPath, 'assets', 'tray.png');
|
const iconPath = isDevelopment ? path.join(__dirname, '../../assets/tray.png') : path.join(process.resourcesPath, 'assets', 'tray.png');
|
||||||
const tray = new Tray(iconPath);
|
const tray = new Tray(iconPath);
|
||||||
tray.setToolTip('中国电信-工作台');
|
tray.setToolTip('中国电信-工作台');
|
||||||
tray.setContextMenu(contextMenu);
|
tray.setContextMenu(contextMenu);
|
||||||
|
@ -4,36 +4,63 @@
|
|||||||
import { contextBridge, ipcRenderer } from 'electron';
|
import { contextBridge, ipcRenderer } from 'electron';
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
// 打开新标签页
|
/**
|
||||||
|
* 在新标签页打开URL
|
||||||
|
* @param callback 回调函数,参数为webContentId和url。其中webContentId是请求打开URL的webview的id。
|
||||||
|
*/
|
||||||
onOpenTab: (callback: (webContentId: number, url: string) => void) => {
|
onOpenTab: (callback: (webContentId: number, url: string) => void) => {
|
||||||
ipcRenderer.on('webview-new-window', (_event, webContentId, url) => callback(webContentId, url));
|
ipcRenderer.on('webview-new-window', (_event, webContentId, url) => callback(webContentId, url));
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取当前屏幕的缩放比例和分辨率
|
/**
|
||||||
getPrimaryDisplay: () => ipcRenderer.invoke('get-primary-display'),
|
* 获取当前屏幕的缩放比例和分辨率
|
||||||
|
* @returns 缩放比例和分辨率
|
||||||
|
*/
|
||||||
|
getPrimaryDisplay: () => ipcRenderer.invoke('get-primary-display') as Promise<Electron.Display>,
|
||||||
|
|
||||||
// 检查URL是否可用
|
/**
|
||||||
|
* 检查URL是否可用
|
||||||
|
* @param url 要检查的URL
|
||||||
|
* @returns 是否可用
|
||||||
|
*/
|
||||||
checkUrlAvailable: (url: string) => ipcRenderer.invoke('check-url-available', url),
|
checkUrlAvailable: (url: string) => ipcRenderer.invoke('check-url-available', url),
|
||||||
|
|
||||||
// 设置webview的cookie
|
/**
|
||||||
|
* 设置webview的cookie
|
||||||
|
* @param url 要设置cookie的URL
|
||||||
|
* @param cookie cookie字符串
|
||||||
|
*/
|
||||||
setWebviewCookie: (url: string, cookie: string) => ipcRenderer.invoke('set-webview-cookie', url, cookie),
|
setWebviewCookie: (url: string, cookie: string) => ipcRenderer.invoke('set-webview-cookie', url, cookie),
|
||||||
|
|
||||||
// 设置 sessionStorage
|
/**
|
||||||
|
* 按键将值设置到sessionStorage
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
setSessionStorage: (key: string, value: string) => {
|
setSessionStorage: (key: string, value: string) => {
|
||||||
window.sessionStorage.setItem(key, value);
|
window.sessionStorage.setItem(key, value);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取 sessionStorage
|
/**
|
||||||
|
* 从sessionStorage中获取指定键的值
|
||||||
|
* @param key 键
|
||||||
|
* @returns 值
|
||||||
|
*/
|
||||||
getSessionStorage: (key: string) => {
|
getSessionStorage: (key: string) => {
|
||||||
return window.sessionStorage.getItem(key);
|
return window.sessionStorage.getItem(key);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 删除 sessionStorage
|
/**
|
||||||
|
* 从sessionStorage中删除指定键的值
|
||||||
|
* @param key 键
|
||||||
|
*/
|
||||||
removeSessionStorage: (key: string) => {
|
removeSessionStorage: (key: string) => {
|
||||||
window.sessionStorage.removeItem(key);
|
window.sessionStorage.removeItem(key);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 清空 sessionStorage
|
/**
|
||||||
|
* 清空sessionStorage
|
||||||
|
*/
|
||||||
clearSessionStorage: () => {
|
clearSessionStorage: () => {
|
||||||
window.sessionStorage.clear();
|
window.sessionStorage.clear();
|
||||||
}
|
}
|
||||||
|
35
src/types/electron.d.ts
vendored
35
src/types/electron.d.ts
vendored
@ -1,11 +1,46 @@
|
|||||||
export interface ElectronAPI {
|
export interface ElectronAPI {
|
||||||
|
/**
|
||||||
|
* 在新标签页打开URL
|
||||||
|
* @param callback 回调函数,参数为webContentId和url。其中webContentId是请求打开URL的webview的id。
|
||||||
|
*/
|
||||||
onOpenTab: (callback: (webContentId: number, url: string) => void) => void;
|
onOpenTab: (callback: (webContentId: number, url: string) => void) => void;
|
||||||
|
/**
|
||||||
|
* 获取当前屏幕的缩放比例和分辨率
|
||||||
|
* @returns 缩放比例和分辨率
|
||||||
|
*/
|
||||||
getPrimaryDisplay: () => Promise<Electron.Display>;
|
getPrimaryDisplay: () => Promise<Electron.Display>;
|
||||||
|
/**
|
||||||
|
* 检查URL是否可用
|
||||||
|
* @param url 要检查的URL
|
||||||
|
* @returns 是否可用
|
||||||
|
*/
|
||||||
checkUrlAvailable: (url: string) => Promise<{ ok: boolean; status: number; error?: string }>;
|
checkUrlAvailable: (url: string) => Promise<{ ok: boolean; status: number; error?: string }>;
|
||||||
|
/**
|
||||||
|
* 设置webview的cookie
|
||||||
|
* @param url 要设置cookie的URL
|
||||||
|
* @param cookie cookie字符串
|
||||||
|
*/
|
||||||
setWebviewCookie: (url: string, cookie: string) => Promise<boolean>;
|
setWebviewCookie: (url: string, cookie: string) => Promise<boolean>;
|
||||||
|
/**
|
||||||
|
* 按键将值设置到sessionStorage
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
setSessionStorage: (key: string, value: string) => void;
|
setSessionStorage: (key: string, value: string) => void;
|
||||||
|
/**
|
||||||
|
* 从sessionStorage中获取指定键的值
|
||||||
|
* @param key 键
|
||||||
|
* @returns 值
|
||||||
|
*/
|
||||||
getSessionStorage: (key: string) => string | null;
|
getSessionStorage: (key: string) => string | null;
|
||||||
|
/**
|
||||||
|
* 从sessionStorage中删除指定键的值
|
||||||
|
* @param key 键
|
||||||
|
*/
|
||||||
removeSessionStorage: (key: string) => void;
|
removeSessionStorage: (key: string) => void;
|
||||||
|
/**
|
||||||
|
* 清空sessionStorage
|
||||||
|
*/
|
||||||
clearSessionStorage: () => void;
|
clearSessionStorage: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user