背景
最近在做一個Web和Electron共用一份代碼的工程,由於使用到了第三方的庫(我們是在線地圖),該庫的認證方式是請求時加key,並且它在后台會校驗referer。
於是問題就來了,Electron是運行在本地的,http請求的時候,是不會帶有授權Web站點的referer的。導致認證失敗,無法調用所需的api接口。
分析
既然HTTP請求發送的時候不帶referer,那么我們給他加上去,是不是就可以了呢?
對策
方法1:自定義HTTP協議,在發送請求時,補上referer
// 注冊自定義協議 protocol.registerStandardSchemes(['app', '自定義協議'], { secure: true }) // 自定義協議的具體實現 protocol.registerHttpProtocol('自定義協議', (req, cb) => { cb({ url: “特定的url地址”, referrer: "http://被授權的referrer頭信息" }) }) // 發送請求時可以使用 自定義協議://url地址 的形式來發送請求
發送請求時可以使用 自定義協議://url地址 的形式來發送請求。當然,我們這個例子里面只是追加了referrer,其實根據實際需求還可以做很多其它事情。
相關api文檔:https://electronjs.org/docs/api/protocol#protocolregisterhttpprotocolscheme-handler-completion
方法2:修改窗口會話中發送請求前的行為
本來以為方法1以及很完美的解決了問題,但是,在自定義協議認證成功后,在api的使用過程中,api內部主動發送了http請求,這時的api請求沒有使用自定義協議,再次認證失敗了。於是我想到有個辦法,很天真的認為可以解決問題。失敗的做法如下:
protocol.interceptHttpProtocol("http", (req, cb) => { // 此處可以追加url是否匹配的邏輯判斷 cb({ url:req.url, referrer: "http://授權的referrer頭信息" }) })
相關api文檔:https://electronjs.org/docs/api/protocol#protocolintercepthttpprotocolscheme-handler-completion
我直接攔截了原生的http協議,追加referrer信息,發生的結果是,http->截獲http->修改后發送http->截獲http->修改后發送http->......發生了無限循環!!!
於是只能另辟蹊徑,尋找其余解決方案。發現了webquest的行為可以捕獲。於是在onBeforeSendHeaders的時機,追加Referer信息。正確的做法如下:
// 需要攔截的URL地址 const xxx_filter = { urls: ["https://*.xxx.com/*", "http://*.yyy.com/*"] } session.defaultSession.webRequest.onBeforeSendHeaders(xxx_filter, (details, callback) => { details.requestHeaders['Referer'] = 'http://授權的referer頭信息' callback({ requestHeaders: details.requestHeaders }); })
相關api文檔:https://electronjs.org/docs/api/web-request
總結
通過對webrequest的捕獲,解決了本次的問題,並且把自定義協議那個案也可以替換掉。webrequest還有好幾個階段的行為可以自定義,可以適用於不同場景的需求。