基於 Github API 的圖牀 Chrome 插件開發全紀錄

image

最近基於 Github API 開發了一款圖牀 Chrome 插件 Picee,如今已經開源並上架 Chrome 應用商店。當中的過程涉及到一些有趣的知識點,故將其記錄下來。javascript

Github地址: https://github.com/jrainlau/p...

Chrome商店下載地址:Piceecss

靈感

平時有寫點東西的習慣,可是奈何一直找不到合適的圖牀。有人推薦以微博或者七牛來作圖牀,可是總給我一種」受制於人「的感受,不知道何時就會被各類限制,好比禁止圖片外鏈等等。後來發現其實 Github 是很是適合作圖牀的,由於倉庫裏的文件均可以經過 https://raw.githubusercontent.com 這個連接直接外鏈以供下載。可是若是爲了寫個文章而每次添加圖片都須要一頓 Git 操做,那麼寫做體驗一定很是很差,若是有更方便的辦法就行了——那就是Github API。html

Github API

Github 提供了一套完善的 API 以供操做,幾乎涵蓋了開發一個完整 Github 客戶端的全部功能。API 分爲 REST 風格的 v3 版本和 GraphQL 風格的 v4 版本。爲了使用方便,我選擇的是 v3 版本。具體的 API 細節能夠在官方文檔查看。vue

要製做一個圖牀應用,咱們只須要用到上傳文件的 API 便可。可是在調用這個 API 以前,首選須要用戶對應用進行受權,也就是所謂的登陸操做。java

受權

對於通常的」查看」操做,是不須要受權的,好比獲取用戶的公開信息,獲取公有倉庫的 issues 等等。可是有兩個場景是須要受權的,其一是任何對於倉庫的「增刪改查」操做(包括提交 issue,評論等);其二則是對於某 IP 有 API 的調用次數限制,若這個 IP 調用 Github API 的次數過多則須要受權。git

那麼受權應該怎麼作呢?官方提供了三種辦法,分別是 BasicoAuth2 tokenoAuth2 key/secretgithub

Basic受權

也就是最傳統的帳號密碼受權方式,咱們能夠在命令行用 curl 來測試之:web

curl -u "帳號:密碼" https://api.github.com

若是是正確的帳號密碼,則會返回一系列的內容,不然會返回錯誤信息。chrome

對於開發來講,我更推薦使用 Postman 來對 API 進行測試:json

image

點開右邊的 code ,能夠看到 JS 代碼:
image

其中 xhr.setRequestHeader("Authorization", "Basic xxxxxx");就是咱們須要設置的受權 header,當中的 xxxxxx 是這麼來的:

btoa(username + ':' + password)

oAuth2 token 受權

對於帳號密碼來講,輕易地在第三方平臺輸入其實並不那麼安全,那麼有沒有辦法既能保障帳戶的安全,又能實現受權的需求呢?答案就是 oAuth token。

簡單來講,oAuth token 至關於用戶提供給第三方的一張受權令牌,第三方經過這張令牌能夠得到用戶所容許使用的一系列權限,可是卻不會知曉用戶的帳號和密碼,因而便得以在有效保障用戶帳號安全的同時,又能方便地對第三方應用進行受權。

在 Github 裏,能夠在這個地方設置生成具備某些權限的 token:

image

最後在 Postman 裏選擇 OAuth 2.0 或者 Bearer Token,而後把這串 token 粘貼進去便可。

image

其中的受權 header 爲 Bearer token

oAuth 2 key/secret受權

這種受權方式是經過生成一對 key/secret,來容許第三方獲取用戶的公開信息,是一種只讀的受權方式,沒法對倉庫進行改寫操做,主要用於第三方登陸,故在這裏不適用。更多關於 key/secret 的內容能夠查看阮一峯的《GitHub OAuth 第三方登陸示例教程》,寫得很是生動詳細。


在瞭解了三種受權方式以後,咱們就能夠進行下一步操做,實現圖片的上傳了。

圖片上傳 API

圖片上傳使用了 content API 的 create-a-file 接口,經過 PUT 發送一條文件內容爲 base64 的請求到指定的倉庫目錄。

image

這裏着重圈出了必須把文件進行 base64 編碼,不然接口調用將會出錯。

經過 btoa('hello world) 方法把 hello world 轉成 base64,而後放在 Postman 裏測試一下:

image

image

看來效果是OK的,接下來就是對圖牀插件進行開發的步驟了。

Chrome 插件開發

除了看官方文檔學習插件開發之外,也能夠參考由@小茗同窗 所寫的《【乾貨】Chrome插件(擴展)開發全攻略》,裏面對於 Chrome 插件的開發有着詳細的敘述,很是值得一讀。

讀完上面推薦的文章以後,我選擇使用 VueJS 進行開發。因爲項目比較簡單,因此我沒有用任何的打包工具,直接經過 script 的方式引入 VueJS。值得注意的是,Chrome 插件不容許行內 script 和行內 style,因此任何的 css 和 js 文件都必須經過本地文件連接的方式去使用。另外因爲咱們的 JS 是運行在 Chrome 環境的,因此能夠放心大膽地使用 es 模塊和 async/await 等高級語法,而無需任何的構建工具參與。

可是在使用 VueJS 的第一步我就遇到了問題,綁定了 new Vue() 的 DOM 元素居然顯示不出來。通過查證,原來 Chrome 插件有 Content Security Policy (CSP) 限制,默認是不支持 eval()new Function() 等方式運行代碼的,而完整版的 VueJS 剛好是這麼幹的(官網有說),因此就出問題了。那麼怎麼解決呢?很簡單,在 manifest.json 裏面聲明一下就行了:

// manifest.json

{
  // ...
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}

這裏我採用的是 popup 形式的插件,彈出來的窗口就是項目所定義的 index.html。若是要調試插件的頁面,能夠直接在插件彈出的窗口點擊右鍵,而後點擊「檢查」,就會彈出咱們熟悉的開發者工具了。若是插件文件有改動,除了從新打開插件之外,咱們也能夠在開發者工具經過 cmd + r 去直接刷新,省去了屢次點擊的麻煩。

功能實現

通過前面的準備,咱們已經掌握瞭如何對 Github API 進行受權而後上傳圖片的辦法,接下來就是在業務邏輯裏去實現它們。我封裝了一下原生的 fetch 方法,讓它更方便調用:

const $fetch = (options) => {
  return window.fetch(options.url, {
    method: options.method || 'GET',
    headers: {
      "Content-Type": "application/json",
      "Authorization": localStorage.getItem('picee_token')
    },
    body: JSON.stringify(options.body) || null,
    mode: 'cors'
  })
    .then(async res => {
      if (res.status >= 200 && res.status < 400) {
        return {
          status: res.status,
          data: await res.json()
        }
      } else {
        return {
          status: res.status,
          data: null
        }
      }
    })
    .catch(e => e)
}

export default $fetch

請求接口時攜帶的受權 header 所需的 token,我把它們存放在插件的 localStorage 下,方便調用。

有了請求接口的方法之後,接下來就要完成選擇圖片和把圖片轉化成 base64 的工做。這裏我複用了另外一個做品裏的 chooseImg.jspaste.js 方法,最終可以支持以選擇、粘貼、拖拽的方式上傳圖片。

剩下的一些功能細節就不贅述了,代碼很是簡單,建議讀者們自行查閱。

應用發佈

準備好了 logo,描述等善後工做以後,就能夠正式提交應用發佈了。咱們能夠在開發者信息中心裏面把插件提交上去,填入必要的信息之後點擊發布,等待審覈完成。可是在此以前,你必須支付5美圓的開發者註冊費,國內的開發者在完成這一步的時候可能會遇到蠻大的困難,這一個問題在知乎也有討論:如何在中國使用信用卡支付「Chrome 網上應用店」開發者註冊費?。我是經過萬能的淘寶搞定的。

在完成註冊以後和發佈之後,就能看到插件的主頁了:

chrome google com_webstore_detail_picee_nmeeieecbmdnilkkaliknhkkakonobbc(iPad)

值得注意的是,剛發佈的插件是暫時不能被搜索出來的,須要等待一段時間之後才能搜索出來。

image

至此,整個插件的開發——發佈流程就已經完成了。