Electron开发实践三,不存在跨域问题

Electron 页面渲染是在 Chromium 浏览器内核中进行的,按理来说应该与常规浏览器一样存在跨域请求的问题,可实际上真的是这样吗。下面一起来看看。

本地文件不受跨域限制

在 Electron 中,应用使用的是本地文件协议(file://),而不是 HTTP 协议。因此,常规浏览器中适用的跨域资源共享(CORS)策略并不完全适用于 Electron。我们可以创建一个简单的 HTML 文件进行对比:

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head></head>
  <body>
    <script>
      fetch('https://vekun.com')
        .then((resp) => resp.text())
        .then((res) => {
          console.log('请求结果', res)
        })
    </script>
  </body>
</html>

当使用常规浏览器打开时,毫无疑问会提示跨域请求失败。

然而,当使用 Electron 加载该页面时,在主线程代码中使用loadFile方法加载本地文件:

js 复制代码
app.whenReady().then(() => {
  win = new BrowserWindow()
  win.loadFile(path.resolve(__dirname, 'index.html'))
})

可以看到请求成功并获得结果。

网络资源受跨域限制

上面是通过loadFile加载本地文件,接下来我们尝试启动一个服务,然后通过loadURL加载页面。我们启动一个在 8080 端口的服务器,并在主线程中将渲染代码修改为:

js 复制代码
win.loadURL('http://localhost:8080')

相信很多人都能猜到结果,这次同样会出现跨域访问失败的情况。

那么,在这种情况下,我们应该如何解决跨域问题呢?下面提供三种处理方式。

使用webPreferences禁用 Web 安全策略

使用 Electron 的webPreferences配置项设置webSecurityfalse,即禁用 Web 安全策略。这样可以允许跨域请求,但会对系统安全性产生风险。

js 复制代码
const win = new BrowserWindow({
  webPreferences: {
    webSecurity: false,
  },
})
win.loadURL('http://localhost:8080')

使用session模块拦截和修改请求:

使用 Electron 的session模块,创建一个新的session来进行跨域请求。通过session对象的webRequest事件来拦截和修改请求,并设置返回请求的 CORS(跨域资源共享)头。

js 复制代码
const filter = {
    urls: ['https://vekun.com/']
  }

  session.defaultSession.webRequest.onHeadersReceived(filter, (details, callback) => {
    details.responseHeaders!['Access-Control-Allow-Origin'] = ['*']
    callback({
      cancel: false,
      responseHeaders: details.responseHeaders
    })
  })

win.loadURL('http://localhost:8080')

在主进程中使用net模块发送 HTTP 请求

在主进程中使用 Electron 的net模块发送 HTTP 请求,该模块不受跨域限制。可以在主进程中通过 IPC 与渲染进程通信,将结果传递给渲染进程。

js 复制代码
ipcMain.handle('fetch', (_event, ...args) => {
  return net.fetch(...args).then((resp) => resp.text())
})

然后在预加载脚本给 Window 对象添加方法。

js 复制代码
contextBridge.exposeInMainWorld('api', {
  fetch: (url: string, data: any = {}) => ipcRenderer.invoke('fetch', url, data),
})

然后在页面中就可以通过window.api.fetch方法进行请求,案例中对请求结果处理逻辑比较简单,你可以按需要添加自己的逻辑。

上面三种处理跨域的问题都比较简单,也不用交给后端开发去处理。当然,还有一种方法可以通过创建代理服务器的方式,不过对于本地文件不受跨域限制情况下使用代理服务器意义不大。

源码:wenyikun/chat-electron-app: A ChatGPT chat application developed using Electron. (github.com)

相关推荐
北海-cherish6 小时前
vue中的 watchEffect、watchAsyncEffect、watchPostEffect的区别
前端·javascript·vue.js
2501_915909067 小时前
HTML5 与 HTTPS,页面能力、必要性、常见问题与实战排查
前端·ios·小程序·https·uni-app·iphone·html5
white-persist8 小时前
Python实例方法与Python类的构造方法全解析
开发语言·前端·python·原型模式
新中地GIS开发老师9 小时前
Cesium 军事标绘入门:用 Cesium-Plot-JS 快速实现标绘功能
前端·javascript·arcgis·cesium·gis开发·地理信息科学
Superxpang9 小时前
前端性能优化
前端·javascript·vue.js·性能优化
左手吻左脸。9 小时前
解决el-select因为弹出层层级问题,不展示下拉选
javascript·vue.js·elementui
左手吻左脸。9 小时前
Element UI表格中根据数值动态设置字体颜色
vue.js·ui·elementui
李白的故乡9 小时前
el-tree-select名字
javascript·vue.js·ecmascript
Rysxt_9 小时前
Element Plus 入门教程:从零开始构建 Vue 3 界面
前端·javascript·vue.js
隐含9 小时前
对于el-table中自定义表头中添加el-popover会弹出两个的解决方案,分别针对固定列和非固定列来隐藏最后一个浮框。
前端·javascript·vue.js