現在,以編程方式在 Electron 中上傳文件,是非常簡單的!

来源:http://www.cnblogs.com/ios122/archive/2017/07/23/7223480.html
-Advertisement-
Play Games

具體到以編碼方式上傳文件這個問題上.這個問題的完整描述應該是類似於這樣: 網站有自己的登錄認證機制,在不需要在對網站登錄機製做任何修改的前提下,如何自動上傳用戶相關的文件,比如用戶頭像? 我們就以自動上傳用戶頭像為例.我們可以假定已經通過某種方式,得到了用戶頭像的本地路徑.--這個大前提,在基於 ... ...


必要的上下文

想儘快熟悉上下文語境的,可以點這裡: https://github.com/electron/electron/issues/749

這段討論,其實本來是討論如何自動設置 input 標簽的值來實現自動選擇文件的.前一段有個 Electon 中自動上傳文件的需求,被 Google 帶到了這個討論地址.雖然,最後當時是採用的不同討論中的本地代理器轉發cookie的策略,但不得不承認,這些討論還是給了自己很大啟發的 -- 雖然暫時並沒有什麼用.

It's near impossible to programmatically upload a file in electron right now.

當時,討論區 @erikmellum 的一句 "現在在Electron 中,以編碼方式上傳文件,幾乎是不可能的",讓我放棄了對 Electron 本身機制的思考.轉而,基於當時 App 已有的本地代理伺服器, 做了另一番嘗試.當然,最後也是成功了.這個機制,等會兒我會簡單描述下.因為它已經不是重點了! 因為已經有了更簡化的方式.

這個問題的關鍵是在於如何獲取完整的 cookie,特別是 session 相關那一部分的 cookie.今天突然又看到 electron 文檔的 session 部分,看到它有一個 cookies 屬性.心想,這個 cookies, 既然是屬於 electron 自有的 api,那豈不是也可以獲取完整的 cookie ?試了下,還真是! 卒~

技術關鍵點分析

Electron,結合了 Node 和 Chromium.在相當程度上,可以認為它同時擁有了 Node 和 Chromium 的能力;另一方面,其實也可以認為,它擁有了 Node 和 Chromium 各自的限制.在 Electron 編碼時,如何理解和運用 Node 和 Chromium 各自的限制和能力,就變得很有趣.如果能進一步地熟練打通 Node 和 Chromium ,真的可以做某些以前很難去想象的事.

具體到以編碼方式上傳文件這個問題上.這個問題的完整描述應該是類似於這樣: 網站有自己的登錄認證機制,在不需要在對網站登錄機製做任何修改的前提下,如何自動上傳用戶相關的文件,比如用戶頭像?

我們就以自動上傳用戶頭像為例.我們可以假定已經通過某種方式,得到了用戶頭像的本地路徑.--這個大前提,在基於 Electron 的App中,非常容易滿足!

對於 Chromium 側的童鞋來說,拿到文件的本地路徑後,是沒有比較簡便的辦法實現文件上傳的. https://github.com/electron/electron/issues/749#issuecomment-145764807 討論中,提到的兩個地址,再結合 https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects 或許應該也是可以的.我沒驗證!

對於 Node 層的同學來說,有了文件路徑,可以很容易地通過 https://www.npmjs.com/package/request 庫來實現文件的上傳,如果他能拿到當前回話的完整 Cookie 的話.當然,這個限制,也是有足夠多的方式來彌補的,比如讓用戶在桌面 App 上,再單獨登錄一次.不管怎樣,解決問題就好.

但是,Electron 提供了一種全新的可能.它讓你可以在 Node 側,直接拿到 Chromium 側的完整 Cookie.然後你就可以使用 Node 的方式,以最精簡的代碼,最符合直覺的方式來處理文件上傳.

好吧,借題插一句:我曾經處理過一個 XML 文件解析的需求.當時搜了各種 Node 庫,都沒太好使的,後來我是直接在 render process 中,直接用 html 的dom 介面去讀取和解析的 xml 文件! -- 當時,被自己的機智驚呆了! 講真, 使用 Electron 來開發桌面 App,你真正需要考慮的不是如何實現某個需求,而是如何以一種更優雅的方式來實現需求! 沒有做不到,只有不敢想啊!!!

一個簡單的實例: 實現開源中國用戶頭像自動更換

效果圖

為了完整演示這一技術可能涉及的特定問題及其解決方案,我們就從真實環境中來構造一個需求: 實現開源中國用戶頭像自動更換. 當然,是不需要 OSC 的研發改任何代碼的前提下!!!

安裝 electron

安裝,建議使用穩定版本 1.3.x 系列的,可能需要 科學上網,才能安裝.基礎的快速入門教程,參考: https://electron.atom.io/docs/tutorial/quick-start/

npm i [email protected] -g

jquery 無效問題.

我們把入門示例中的url換為 osc 官方的功能變數名稱:

win.loadURL("https://www.oschina.net/")

cd 到項目目錄,執行:

electron .

此時 electron 就運行起來了,不過當你切換到登錄頁後, devtool 視窗,應該會報錯:

Uncaught ReferenceError: $ is not defined

錯誤的原因,可以參考: https://github.com/electron/electron/issues/254 不過解決方式,都不適用於這裡的場景.因為我不能直接修改 OSC 網站源碼.

不過 Electron 創建視窗時,提供了一個 preload 參數,允許註入一個 js 文件到網頁上下中:

  win = new BrowserWindow({width: 1300, height: 720, webPreferences:{
    preload:path.resolve("./osc-preload.js")
  }})

然後,我們可以重寫在註入的js中,重寫 window 的 $ 和 jquery 屬性的 getter 方法:

Object.defineProperties(window,{
    "$":{
            get: function () {
                return require("jquery")
            },
            configurable : true
        },
      "jQuery":{
              get: function () {
                  return require("jquery");
              },
              configurable : true
          }
    });

此處,之所以是重寫getter,而不是直接賦值,是因為 jquery 依賴於特定的 dom 結構,但是預註入的js文件在執行時,是沒有任何 dom 結構的.註入的js文件,執行時機非常早,甚至早過 dom 或任意其他css/js 文件 的載入或渲染.

有關重寫 getter 和 setter 方法的技術細節,大家可以參考這裡: https://segmentfault.com/a/1190000003882976

尋找jquery版本

當然,此處需要我們先在本地項目中,先安裝 jquery 依賴,從 osc 源碼中分析出,它用的 2.2.4 版本,我們最好也安裝對應版本:

npm i [email protected] --save

找到頭像上傳介面

發現頭像上傳介面

這個很容易,只要通過 ctrl/cmd + alt + i 快捷鍵打開devtool,然後自己替換下頭像,找到那個 ajax 請求就可以了.

我們註意到 formData 主要有 img 和 user_code 兩部分構成.

構造 img 欄位

其實就是一個圖片的 base 編碼, Node 搞這個,輕輕鬆啊.
先安裝一個工具庫: base64-img

npm install base64-img --save

然後:

/* 我們有足夠豐富的方式來獲取或計算圖片的路徑,此處預設採用的方式就是:
當前目錄下的 test.jpeg 圖片.
另外,此處文件註意使用 jpeg 尾碼.這要是 OSC 本身的限制.*/
const imgPath = path.resolve(__dirname,"./test.jpeg")

/* 此處,將文件轉換為 base64,只是因為 osc 的頭像變更介面,設計如此!! */
const imgData = base64Img.base64Sync(imgPath)

分析並獲取 user_code

分析並獲取 user_code

你要相信,任何在 Electron 打開的網站,即時你不是網站的擁有者,也可以獲取比網站的前端研發人員更多的信息. Electron 的機制使然.

只要在 devtool 的源碼區域,簡單搜索下,就很容易發現 user_code 的來源.壓縮後的源碼,如果看著不輸入,可以點擊源碼視圖區左下角的格式化按鈕 {} 格式化一下.

所以獲取 user_code 的代碼,就是:

    g = $("val[data-name=user_code]").data("value"),

Electron 有想成的 API 可以用.Cookie 操作的文檔,參見:https://electron.atom.io/docs/api/cookies/

const { session } = require('electron').remote

session.defaultSession.cookies.get({
        url: window.location.href
    }, (error, cookies) => {
      console.log(cookies)
    })

使用 request 庫發送頭像更新請求

request 的詳細文檔,參考: https://www.npmjs.com/package/request.需要先安裝依賴:

npm i request --save
const request = require("request")

request({
    url: `https://my.oschina.net/action/user/save_portrait_new`,
    method: "POST",
    formData: {
        img: imgData,
        user_code: userCode
    },
    headers: {
        "cookie": cookieStr
    }
}, function(err, response, body) {
  console.log(err, response, body)

  const {error} = JSON.parse(body)
  if ( ! error) {
    window.location.reload()
  }
})

實例完整源碼

感興趣的童鞋,記得 Star 關註下 !!!

https://github.com/ios122/demo-electron-share-cookie

這個思考,主要是基於當期 App 的現狀 -- 已經有了一個用於加速靜態資源訪問速度的用作緩存功能的本地代理伺服器,還有就是當時也對 Electron 的 session 和 cookie 的介面,不太熟悉, 而採用的臨時措施.但畢竟可用,順便說下.其中的本地代理伺服器部分,還是有一定參考價值的.

關於本地代理伺服器,大家可以看下 微信小程式開發工具,會看到它的網路請求的 remote address 都是本地地址,很明顯它加了本地代理伺服器.

本地代理伺服器本身,可以使用 https://www.npmjs.com/package/http-proxy 這個庫.

Electron 想要支持設置網路代理,主要是用到 https://electron.atom.io/docs/api/session/#sessetproxyconfig-callback 介面.唯一主要註意的是,這個介面必須在 main process 調用,才會生效.

使用本地代理伺服器獲取完整 cookie 的思路是: 約定某個url路徑,比如 /-fetch-all-cookies 為獲取 cookie 的路徑 --> 前端發送 ajax 請求到 /-fetch-all-cookies --> 本地代理伺服器,攔截到請求,如果發現路徑是 /-fetch-all-cookies,就把當次請求的 header 中的cookie 部分,作為返回值返回 --> 前端獲取到完整 cookie --> 前端調用 request 庫,上傳文件.

雖然不是最優最簡方案,但或許可以算得上是 腦洞開的最大的方案!!! O(∩_∩)O哈哈哈~

參考鏈接:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、首先是喜聞樂見的position方法,經典且萬能,用法如下: 不需要水平居中可以去掉left和margin-left。 劃重點:需要父元素和子元素都定義寬高,自適應是不可能自適應的,這輩子都不可能自適應的。 二、 display:table-cell能夠使大小不固定的元素實現垂直居中佈局,先來一 ...
  • //首先寫一個導航欄樣式 .nav{ width:560px; height: 50px; font:bold 0/50px Arial; text-align:center; margin:40px auto 0; background: #f65f57; border-radius:10px;/ ...
  • 我們扒取到網站源碼很多時候發現路徑是採用相對路徑,這時候我們就需要採用base標簽了,用法非常簡單, <base href="我們扒取網站的功能變數名稱"/> 這時相對路徑就相對於這個網站功能變數名稱了,就可以正常顯示效果了 ...
  • js獲取單選按鈕的值 js獲取覆選框的值 ...
  • [1]安裝 [2]命令行 [3]標簽 [4]內容 [5]屬性 [6]註釋 [7]代碼 [8]條件 [9]迴圈 [10]混入 [11]包含 [12]繼承 [13]簡易模板 ...
  • 在平時的開發項目中,難免接觸前端的知識,需要寫介面,有時候用到js中的ajax跨越請求,總結了ajax的寫法。 開始之前,需要準備兩個文件,ajax.php ;ajax.html 1.ajax的基本步驟(ajax.php) ajax,有同步非同步的區別?非同步:把小弟派出去了,什麼時候回來,什麼時候處理 ...
  • React在Github上已經有接近70000的 star 數了,是目前最熱門的前端框架。而我學習React也有一段時間了,現在就開始用 React+Redux 進行實戰! 上回說到使用Redux-saga 管理 Redux 應用非同步操作,應用還是只有一個首頁.現在開始構建一個新的投稿頁面並使用 R ...
  • Callbacks 模塊並不是必備的模塊,其作用是管理回調函數,為 Defferred 模塊提供支持,Defferred 模塊又為 Ajax 模塊的 風格提供支持,接下來很快就會分析到 Ajax模塊,在此之前,先看 Callbacks 模塊和 Defferred 模塊的實現。 源碼版本 本文閱讀的源 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...