Electron Squirrel自动更新遇308永久重定向错误,如何强制下载?
问题
为Electron应用开发自动更新功能,采用Hazel作为更新服务器,严格遵循Electron官方更新指南操作,但测试时,Squirrel-CheckForUpdate.log文件中持续出现(308) Permanent Redirect错误。日志显示下载指定URL时触发该重定向错误,最终导致未处理聚合异常。测试该URL在浏览器中可成功下载RELEASES文件,但确实存在308状态码。
相关代码:
function checkForUpdates() { if (app.isPackaged){ const server = config.hazelUpdateURL; const url = `${server}/update/${process.platform}/${app.getVersion()}`; autoUpdater.setFeedURL({ url }); autoUpdater.checkForUpdates(); } } autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => { dialog.showMessageBox({ type: 'info', buttons: ['Restart', 'Later'], title: 'Application Update', message: process.platform === 'win32' ? releaseNotes : releaseName, detail: 'A new version of the Crooms Bell Schedule has been downloaded. Restart the application to apply the updates.' }).then((returnValue) => { if (returnValue.response === 0) autoUpdater.quitAndInstall() }); }) autoUpdater.on('error', (message) => { console.error('There was a problem updating the application'); console.error(message); }); checkForUpdates();
日志内容:
[10/12/23 11:54:19] info: FileDownloader: Downloading url: https://cbsh-updater.vercel.app//update/win32/1.0.2/releases?id=bellschedoverlay&localversion=1.0.2&arch=amd64 [10/12/23 11:54:19] warn: IEnableLogger: Failed to download url: https://cbsh-updater.vercel.app//update/win32/1.0.2/releases?id=bellschedoverlay&localversion=1.0.2&arch=amd64: System.Net.WebException: The remote server returned an error: (308) Permanent Redirect.
[10/12/23 11:54:19] info: CheckForUpdateImpl: Download resulted in WebException (returning blank release list): System.Net.WebException: The remote server returned an error: (308) Permanent Redirect.
[10/12/23 11:54:19] fatal: Finished with unhandled exception: System.AggregateException: One or more errors occurred. ---> System.Net.WebException: The remote server returned an error: (308) Permanent Redirect.
解决方案
1. 修复URL重复斜杠问题
日志中的URL存在//update重复斜杠,这是因为config.hazelUpdateURL末尾可能带了斜杠,拼接时导致重复。先修正URL生成逻辑:
function checkForUpdates() { if (app.isPackaged){ // 移除服务器地址末尾的斜杠,避免拼接时出现重复 const server = config.hazelUpdateURL.replace(/\/$/, ''); const url = `${server}/update/${process.platform}/${app.getVersion()}`; autoUpdater.setFeedURL({ url }); autoUpdater.checkForUpdates(); } }
多数服务器会对重复斜杠返回308重定向,修正后大概率能解决问题。
2. 强制处理308重定向
如果修正URL后仍存在308错误,是因为Electron Windows平台依赖的Squirrel.Windows默认不支持308状态码的重定向,可通过以下方式解决:
方式一:自定义下载逻辑(推荐)
跳过autoUpdater的默认下载流程,用Node.js工具库自己处理下载,自动跟随重定向:
import axios from 'axios'; import { autoUpdater, dialog, app } from 'electron'; import * as fs from 'fs'; import * as path from 'path'; async function checkForUpdatesCustom() { if (!app.isPackaged) return; const server = config.hazelUpdateURL.replace(/\/$/, ''); const updateUrl = `${server}/update/${process.platform}/${app.getVersion()}`; try { // axios默认会跟随所有重定向(包括308) const updateResp = await axios.get(updateUrl, { maxRedirects: 5 }); const updateInfo = updateResp.data; if (updateInfo.url) { // 下载更新包到临时目录 const tempPath = app.getPath('temp'); const updateFilePath = path.join(tempPath, 'app-update.exe'); const writer = fs.createWriteStream(updateFilePath); const downloadResp = await axios.get(updateInfo.url, { responseType: 'stream', maxRedirects: 5 }); downloadResp.data.pipe(writer); await new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); // 提示用户安装 dialog.showMessageBox({ type: 'info', buttons: ['Restart', 'Later'], title: '应用更新', message: process.platform === 'win32' ? updateInfo.releaseNotes : updateInfo.name, detail: '更新包已下载完成,重启应用即可安装更新。' }).then(res => { if (res.response === 0) autoUpdater.quitAndInstall(); }); } } catch (err) { console.error('更新检查失败:', err); } } // 替换原checkForUpdates调用 checkForUpdatesCustom();
方式二:设置Squirrel环境变量(仅Windows)
通过环境变量强制Squirrel跟随重定向,需在应用启动时设置:
app.on('ready', () => { // 让Squirrel允许跟随所有重定向 process.env.SQUIRREL_FOLLOW_REDIRECTS = 'true'; checkForUpdates(); });
注意:此方法依赖Squirrel版本,部分旧版本可能不支持该环境变量。
3. 捕获未处理异常
日志中出现未处理聚合异常,需在主进程添加全局异常捕获:
// 捕获未处理同步异常 process.on('uncaughtException', err => { console.error('未捕获异常:', err); }); // 捕获未处理Promise拒绝 process.on('unhandledRejection', (reason, promise) => { console.error('未处理Promise拒绝:', reason, promise); });
内容的提问来源于stack exchange,提问作者kone
相关产品推荐
相关产品推荐

