成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

安息吧 REST API,GraphQL 長存

Big_fat_cat / 2801人閱讀

摘要:需要哪些數(shù)據(jù),與開發(fā)人員在中聲明該數(shù)據(jù)的方式之間存在緊密的聯(lián)系。該大致表示了層可以響應(yīng)的范圍。為了解決多次往返的問題,讓響應(yīng)服務(wù)器只是作為一個(gè)端點(diǎn)。它需要一種語言來處理自定義請(qǐng)求,并響應(yīng)該自定義請(qǐng)求的數(shù)據(jù)。一旦安裝,移動(dòng)應(yīng)用可能會(huì)持續(xù)使用同

首發(fā)于眾成翻譯

即使與 REST API 打交道這么多年,當(dāng)我第一次了解到 GraphQL 和它試圖解決的問題時(shí),我還是禁不住把本文的標(biāo)題發(fā)在了 Twitter 上。

請(qǐng)別會(huì)錯(cuò)意。我不是在說 GraphQL 會(huì)“殺死” REST 或別的類似的東西。REST 可能永遠(yuǎn)不會(huì)消失,就像 XML 從沒消失過一樣。我只是認(rèn)為 GraphQL 之于 REST,正如 JSON 之于 XML 那般。

本篇文章實(shí)際上并沒有100%贊成 GraphQL。后文會(huì)有一個(gè)專門的章節(jié)來闡述 GraphQL 的靈活性成本,更高的靈活性意味著更高的成本。

我喜歡“始終以 WHY 開頭”,所以讓我們開始吧。

摘要:為什么我們需要 GraphQL ?

GraphQL 解決的最重要的3個(gè)問題分別是:

需要進(jìn)行多次往返以獲取視圖所需的數(shù)據(jù):使用 GraphQL,你可以隨時(shí)通過單次往返服務(wù)器獲取視圖所需的所有初始數(shù)據(jù)。要使用 REST API 實(shí)現(xiàn)相同的功能,我們需要引入難以管理和擴(kuò)展的非結(jié)構(gòu)化參數(shù)和條件。

客戶端依賴于服務(wù)端:客戶端使用 GraphQL 作為請(qǐng)求語言:(1) 消除了服務(wù)器對(duì)數(shù)據(jù)形狀或大小進(jìn)行硬編碼的需要,(2) 將客戶端與服務(wù)端分離。這意味著我們可以把客戶端與服務(wù)端分離開來,多帶帶進(jìn)行維護(hù)和改進(jìn)。

糟糕的前端開發(fā)體驗(yàn):使用 GraphQL,開發(fā)人員可以聲明式地來表達(dá)其用戶界面的數(shù)據(jù)需求。他們聲明他們需要什么數(shù)據(jù),而不是如何獲取它。UI 需要哪些數(shù)據(jù),與開發(fā)人員在 GraphQL 中聲明該數(shù)據(jù)的方式之間存在緊密的聯(lián)系。

本文將詳細(xì)介紹 GraphQL 如何解決所有這些問題。

在我們開始之前,如果你還不熟悉 GraphQL,可以從簡單的定義開始。

什么是 GraphQL ?

GraphQL 是一門語言。如果我們將 GraphQL 嵌入某個(gè)軟件應(yīng)用,該應(yīng)用能夠聲明式地將任意必需的數(shù)據(jù)傳遞給同樣使用 GraphQL 的后端數(shù)據(jù)服務(wù)。

就像一個(gè)小孩可以很快學(xué)會(huì)一門新的語言 - 而成年人則相對(duì)沒那么容易學(xué)會(huì) - 從頭開始使用 GraphQL 會(huì)比引入 GraphQL 到一個(gè)成熟的應(yīng)用中更容易。

要讓一個(gè)數(shù)據(jù)服務(wù)能夠使用 GraphQL,我們需要實(shí)現(xiàn)一個(gè)運(yùn)行時(shí)層,并將其暴露給想要與服務(wù)端通信的客戶端。將服務(wù)器端的這一層看作簡單的 GraphQL 語言的翻譯器,或者代表數(shù)據(jù)服務(wù)的 GraphQL 代理。GraphQL 不是存儲(chǔ)引擎,所以它并不是一個(gè)獨(dú)立的解決方案。這就是為什么我們不能僅有一個(gè) GraphQL 的服務(wù)器,我們還需要實(shí)現(xiàn)一個(gè)翻譯運(yùn)行時(shí)。

這個(gè)抽象層可以用任意語言編寫,它定義了一個(gè)通用的基于圖形的 schema 來發(fā)布它所代表的數(shù)據(jù)服務(wù)的功能。使用 GraphQL 的客戶端程序可以通過其功能查詢?cè)?schema。這種方法使得客戶端與服務(wù)端解耦,并允許其兩者獨(dú)立開發(fā)和擴(kuò)展。

GraphQL 請(qǐng)求可以是查詢(讀取操作)或突變(寫入操作)。對(duì)于這兩種情況,請(qǐng)求都是一個(gè)簡單的字符串,GraphQL 服務(wù)可以使用指定格式的數(shù)據(jù)解釋,執(zhí)行和解析。通常用于移動(dòng)和 Web 應(yīng)用的響應(yīng)格式為 JSON

什么是 GraphQL?(大白話版)

GraphQL 為數(shù)據(jù)通信而生。你有一個(gè)客戶端和一個(gè)服務(wù)器,它們需要相互通信??蛻舳诵枰嬷?wù)器需要哪些數(shù)據(jù),服務(wù)器需要用實(shí)際的數(shù)據(jù)來滿足客戶端的數(shù)據(jù)需求。GraphQL 是此種通信方式的中介。

截圖來源于我的 Pluralsight 課程 - 使用 GraphQL 構(gòu)建可擴(kuò)展的 API。

你可能會(huì)問,為什么客戶端不直接與服務(wù)器通信呢? 當(dāng)然可以。

在客戶端和服務(wù)器之間加入 GraphQL 層的考量有多種原因。其中之一,也許是最受歡迎的原因便是效率??蛻舳送ǔP枰蚍?wù)器請(qǐng)求多個(gè)資源,而服務(wù)器會(huì)用單個(gè)資源進(jìn)行響應(yīng)。所以客戶端的請(qǐng)求最終會(huì)多次往返服務(wù)器,以收集所有需要的數(shù)據(jù)。

使用 GraphQL,我們基本上可以將這種多個(gè)請(qǐng)求的復(fù)雜度轉(zhuǎn)移到服務(wù)器端,并且通過 GraphQL 層處理它。客戶端向 GraphQL 層發(fā)起單個(gè)請(qǐng)求,并獲得一個(gè)完全符合客戶端需求的響應(yīng)。

引入 GraphQL 層有諸多好處。例如,一大好處便是能與多個(gè)服務(wù)進(jìn)行通信。當(dāng)你有多個(gè)客戶端請(qǐng)求多個(gè)服務(wù)的數(shù)據(jù)時(shí),中間的 GraphQL 層可以簡化和標(biāo)準(zhǔn)化此通信過程。盡管這并不是拿來與 REST API 作比較的一個(gè)重點(diǎn) - 因?yàn)檫@很容易實(shí)現(xiàn),而 GraphQL 運(yùn)行時(shí)提供了一種結(jié)構(gòu)化和標(biāo)準(zhǔn)化的方式。

截圖來源于我的 Pluralsight 課程 - 使用 GraphQL 構(gòu)建可擴(kuò)展的 API。

我們可以讓客戶端與 GraphQL 層通信,而不是直接連接兩個(gè)不同的數(shù)據(jù)服務(wù)(如上面的幻燈片中那樣)。然后 GraphQL 層將與兩個(gè)不同的數(shù)據(jù)服務(wù)進(jìn)行通信。GraphQL 首先將客戶端從需要與多種語言進(jìn)行通信中隔離,并將單個(gè)請(qǐng)求轉(zhuǎn)換為使用不同語言的多個(gè)服務(wù)的多個(gè)請(qǐng)求。

想象一下,有三個(gè)人說三種不同的語言,并擁有不同的知識(shí)類型。然后,只有把所有三個(gè)人的知識(shí)結(jié)合在一起才能得到回答。如果你有一個(gè)能說這三種語言翻譯人員,那么把你的問題的答案結(jié)合在一起就很容易。這正是 GraphQL 運(yùn)行時(shí)所做的。

計(jì)算機(jī)尚未聰明到能回答任何問題(至少現(xiàn)在還沒有),所以它們必須遵循既定的算法。這就是為什么我們需要在 GraphQL 運(yùn)行時(shí)中定義一個(gè) schema,并且該 schema 能被客戶端所使用。

這個(gè) schema 基本可以視為一個(gè)功能文檔,其中列出了客戶端可以請(qǐng)求 GraphQL 層的所有查詢。因?yàn)槲覀冊(cè)谶@里使用的是節(jié)點(diǎn)的圖,所以使用 schema 會(huì)帶來一些靈活性。該 schema 大致表示了 GraphQL 層可以響應(yīng)的范圍。

還不夠清楚?我們可以說 GraphQL 其實(shí)根本就是:REST API 的接替者。所以讓我回答一下你最有可能問的問題。

REST API 有什么問題?

REST API 最大的問題是其多端點(diǎn)的本質(zhì)。這要求客戶端進(jìn)行多次往返以獲取數(shù)據(jù)。

REST API 通常是端點(diǎn)的集合,其中每個(gè)端點(diǎn)代表一個(gè)資源。因此,當(dāng)客戶端需要獲取多個(gè)資源的數(shù)據(jù)時(shí),需要對(duì) REST API 進(jìn)行多次往返,以將其所需的數(shù)據(jù)放在一起。

在 REST API 中,沒有客戶端請(qǐng)求語言??蛻舳藷o法控制服務(wù)器返回的數(shù)據(jù)。沒有任何語言可以這樣做。更確切地說,可用于客戶端的語言非常有限。

例如,READ REST API 端點(diǎn)可能是

GET /ResouceName ——從該資源獲取所有記錄的列表;

GET /ResourceName/ResourceID ——獲取該 ID 標(biāo)識(shí)的單條記錄。

例如,客戶端不能指定為該資源中的記錄選擇哪些字段。這意味著 REST API 服務(wù)將始終返回所有字段,而不管客戶端實(shí)際需要哪些。GraphQL 針對(duì)這個(gè)問題定義的術(shù)語是超量獲取不需要的信息。這對(duì)客戶端和服務(wù)器而言都是網(wǎng)絡(luò)和內(nèi)存資源的浪費(fèi)。

REST API 的另一大問題是版本控制。如果你需要支持多個(gè)版本,那通常意味著需要新的端點(diǎn)。而在使用和維護(hù)這些端點(diǎn)時(shí)會(huì)導(dǎo)致諸多問題,并且這可能導(dǎo)致服務(wù)器上的代碼冗余。

上面提到的 REST API 的問題正是 GraphQL 試圖要解決的問題。它們當(dāng)然不是 REST API 的所有問題,我也不想討論 REST API 是什么。我主要討論的是比較流行的基于資源的 HTTP 端點(diǎn) API。這些 API 中的每一個(gè)最終都會(huì)變成一個(gè)具有常規(guī) REST 端點(diǎn) + 由于性能原因而制定的自定義特殊端點(diǎn)的組合。這就是為什么 GraphQL 提供了更好的選擇。

GraphQL如何做到這一點(diǎn)?

GraphQL 背后有很多概念和設(shè)計(jì)決策,但最重要的可能是:

GraphQL schema 是強(qiáng)類型 schema。要?jiǎng)?chuàng)建一個(gè) GraphQL schema,我們要定義具有類型字段。這些類型可以是原語的或者自定義的,并且 schema 中的所有其他類型都需要類型。這種豐富的類型系統(tǒng)帶來豐富的功能,如擁有內(nèi)省 API,并能夠?yàn)榭蛻舳撕头?wù)器構(gòu)建強(qiáng)大的工具。

GraphQL 使用圖與數(shù)據(jù)通信,數(shù)據(jù)自然是圖。如果需要表示任何數(shù)據(jù),右側(cè)的結(jié)構(gòu)便是圖。GraphQL 運(yùn)行時(shí)允許我們使用與該數(shù)據(jù)的自然圖形式匹配的圖 API 來表示我們的數(shù)據(jù)。

GraphQL 具有表達(dá)數(shù)據(jù)需求的聲明性。GraphQL 為客戶端提供了一種聲明式語言,以便表達(dá)它們的數(shù)據(jù)需求。這種聲明性創(chuàng)造了一個(gè)關(guān)于使用 GraphQL 語言的內(nèi)在模型,它接近于我們用英語考慮數(shù)據(jù)需求的方式,并且它讓使用 GraphQL API 比備選方案(REST API)容易得多。

最后一個(gè)概念解釋了為什么我個(gè)人認(rèn)為 GraphQL 是一個(gè)規(guī)則顛覆者的原因。

這些都是高層次的概念。讓我們進(jìn)一步了解一些細(xì)節(jié)。

為了解決多次往返的問題,GraphQL 讓響應(yīng)服務(wù)器只是作為一個(gè)端點(diǎn)。本質(zhì)上,GraphQL 將自定義端點(diǎn)的思想運(yùn)用到極致,即讓整個(gè)服務(wù)器成為一個(gè)可以回復(fù)所有數(shù)據(jù)請(qǐng)求的自定義端點(diǎn)。

與單一端點(diǎn)概念相關(guān)的另一大概念是使用該自定義的單個(gè)端點(diǎn)所需的富客戶端請(qǐng)求語言。沒有客戶端請(qǐng)求語言,單個(gè)端點(diǎn)是沒有用的。它需要一種語言來處理自定義請(qǐng)求,并響應(yīng)該自定義請(qǐng)求的數(shù)據(jù)。

擁有客戶端請(qǐng)求語言意味著客戶端將處于控制之中。它們可以明確地請(qǐng)求它們需要什么,服務(wù)器將會(huì)正確應(yīng)答它們請(qǐng)求的內(nèi)容。這解決了超量獲取的問題。

對(duì)于版本控制,GraphQL 的做法很有趣。我們可以完全避免版本控制。本質(zhì)上,我們可以添加新的字段,而不需要?jiǎng)h除舊的字段,因?yàn)槲覀冇幸粋€(gè)圖,并且我們可以通過添加更多的節(jié)點(diǎn)來靈活地?cái)U(kuò)展圖。因此,我們可以在圖上留下舊的 API,并引入新的 API,而不會(huì)將其標(biāo)記為新版本。API 只會(huì)增長,而不會(huì)有版本。

這對(duì)于移動(dòng)客戶端尤其重要,因?yàn)槲覀儫o法控制它們正在使用的 API 版本。一旦安裝,移動(dòng)應(yīng)用可能會(huì)持續(xù)使用同一個(gè)舊版 API 很多年。對(duì)于 Web,則很容易控制 API 的版本,因?yàn)槲覀冎恍柰扑托碌拇a即可。然而對(duì)于移動(dòng)應(yīng)用,這很難做到。

還不完全信服?要不我們用實(shí)際的例子來對(duì) GraphQL 和 REST 做個(gè)一對(duì)一的比較?

RESTful APIs vs GraphQL APIs?—?示例

假設(shè)我們是負(fù)責(zé)構(gòu)建展示“星球大戰(zhàn)”電影和角色的嶄新用戶界面的開發(fā)者。

我們負(fù)責(zé)構(gòu)建的第一個(gè) UI 很簡單:顯示單個(gè)星球大戰(zhàn)人物的信息。例如,達(dá)斯·維德(Darth Vader),以及該角色參演的所有電影。這個(gè)視圖需要顯示人物的姓名,出生年份,星球名稱以及所有他們參演的電影的名稱。

就是這么簡單,我們只要處理3種不同的資源:人物,星球和電影。這些資源之間的關(guān)系也很簡單,任何人都能猜到這里的數(shù)據(jù)形狀。人物對(duì)象從屬于一個(gè)星球?qū)ο?,并且具有一個(gè)或多個(gè)電影對(duì)象。

這個(gè) UI 的 JSON 數(shù)據(jù)可能類似于:

{
  "data": {
    "person": {
      "name": "Darth Vader",
      "birthYear": "41.9BBY",
      "planet": {
        "name": "Tatooine"
      },
      "films": [
        { "title": "A New Hope" },
        { "title": "The Empire Strikes Back" },
        { "title": "Return of the Jedi" },
        { "title": "Revenge of the Sith" }
      ]
    }
  }
}

假設(shè)某個(gè)數(shù)據(jù)服務(wù)給我們提供了該數(shù)據(jù)的確切結(jié)構(gòu),這有一種使用 React.js 表示它的視圖的方式:

// 容器組件:
// PersonProfile 組件:
Name: {person.name}
Birth Year: {person.birthYear}
Planet: {person.planet.name}
Films: {person.films.map(film => film.title)}

這是一個(gè)很簡單的例子,雖然我們對(duì)星球大戰(zhàn)的觀影經(jīng)驗(yàn)可能有所幫助,但 UI 和數(shù)據(jù)之間的關(guān)系其實(shí)是非常清晰的。UI 使用了我們假想的 JSON 數(shù)據(jù)對(duì)象中的所有“鍵”。

現(xiàn)在我們來看看如何使用 RESTful API 請(qǐng)求這些數(shù)據(jù)。

我們需要獲取單個(gè)人物的信息,并且假定我們知道該人物的 ID,則 RESTful API 會(huì)將該信息暴露為:

GET - /people/{id}

這個(gè)請(qǐng)求將返回給我們?cè)撊宋锏男彰錾砟攴莺推渌嘘P(guān)信息。一個(gè)設(shè)計(jì)良好的 RESTful API 還會(huì)返回給我們?cè)撊宋锏男乔?ID 和參演的所有電影 ID 的數(shù)組。

這個(gè)請(qǐng)求的 JSON 響應(yīng)可能是這樣的:

{
  "name": "Darth Vader",
  "birthYear": "41.9BBY",
  "planetId": 1,
  "filmIds": [1, 2, 3, 6],
  *** 其他我們暫不需要的信息 ***
}

然后為了獲取星球的名稱,我們?cè)僬?qǐng)求:

GET - /planets/1

然后為了獲取電影名,我們發(fā)出請(qǐng)求:

GET - /films/1
GET - /films/2
GET - /films/3
GET - /films/6

一旦我們獲取了來自服務(wù)器的所有6個(gè)響應(yīng),我們便可以將它們組合起來,以滿足我們的視圖所需的數(shù)據(jù)。

除了我們必須做6次往返以滿足一個(gè)簡單的用戶界面的簡單數(shù)據(jù)需求的事實(shí),我們獲取數(shù)據(jù)的方法是命令式的。我們給出了如何獲取數(shù)據(jù)以及如何處理它以使其準(zhǔn)備好渲染視圖的說明。

如果你不明白我的意思,你可以自己動(dòng)手嘗試一下。星球大戰(zhàn)數(shù)據(jù)有一個(gè) RESTful API,目前由 http://swapi.co/ 托管??梢匀L試使用它構(gòu)建我們的人物數(shù)據(jù)對(duì)象。數(shù)據(jù)的鍵可能有所不同,但是 API 端點(diǎn)是一樣的。你需要執(zhí)行6次 API 調(diào)用。此外,你將不得不超量獲取視圖不需要的信息。

當(dāng)然,這只是 RESTful API 對(duì)于此數(shù)據(jù)的一個(gè)實(shí)現(xiàn)。可能會(huì)有更好的實(shí)現(xiàn),能使這個(gè)視圖更容易實(shí)現(xiàn)。例如,如果 API 服務(wù)器實(shí)現(xiàn)了資源嵌套,并且表明了人物與電影之間的關(guān)系,則我們可以通過以下方式讀取電影數(shù)據(jù):

GET - /people/{id}/films

然而,一個(gè)純粹的 RESTful API 服務(wù)器很可能不會(huì)像這般實(shí)現(xiàn),并且我們需要讓我們的后端工程師為我們額外創(chuàng)建這個(gè)自定義的端點(diǎn)。這就是擴(kuò)展 RESTful API 的現(xiàn)實(shí)——我們不得不添加自定義端點(diǎn),以有效滿足不斷增長的客戶端需求。然而管理像這樣的自定義端點(diǎn)是很困難的一件事。

現(xiàn)在來看看 GraphQL 的實(shí)現(xiàn)方式。服務(wù)器端的 GraphQL 包含了自定義端點(diǎn)的思想,并將其運(yùn)用到極致。服務(wù)器將只是單個(gè)端點(diǎn),而通道不再重要。如果我們通過 HTTP 執(zhí)行此操作,那么 HTTP 方法肯定也不重要。假設(shè)我們有單個(gè) GraphQL 端點(diǎn)通過 HTTP 暴露在 /graphql

由于我們希望在單次往返中請(qǐng)求我們所需的數(shù)據(jù),所以我們需要一種表達(dá)我們對(duì)服務(wù)器端完整數(shù)據(jù)需求的方式。我們使用 GraphQL 查詢來做:

GET or POST - /graphql?query={...}

一個(gè) GraphQL 查詢只是一個(gè)字符串,但它必須包括我們需要的所有數(shù)據(jù)。這就是聲明式的好處。

在英語中,我們?nèi)绾温暶魑覀兊臄?shù)據(jù)需求:我們需要一個(gè)人物的姓名,出生年份,星球名稱和所有電影名。在 GraphQL 中,這被轉(zhuǎn)換為:

{
  person(ID: ...) {
    name,
    birthYear,
    planet {
      name
    },
    films {
      title
    }
  }
}

再讀一遍英文表述的需求,并將其與 GraphQL 查詢進(jìn)行比較。它們及其相似?,F(xiàn)在,將此 GraphQL 查詢與我們最開始使用的原始 JSON 數(shù)據(jù)進(jìn)行比較。會(huì)發(fā)現(xiàn),GraphQL 查詢就是 JSON 數(shù)據(jù)的確切結(jié)構(gòu),除了沒有所有“值”部分。如果我們根據(jù)問答關(guān)系來考慮這個(gè)問題,那么問題就是沒有答案的答案聲明。

如果答案是:

離太陽最近的行星是水星。

這個(gè)問題的一個(gè)很好的表述方式是同樣的沒有答案部分的聲明:

(什么是)離太陽最近的行星?

同樣的關(guān)系也適用于 GraphQL 查詢。采用 JSON 響應(yīng),移除所有“答案”部分(鍵所對(duì)應(yīng)的值),最后得到一個(gè)非常適合代表關(guān)于該 JSON 響應(yīng)的問題的 GraphQL 查詢。

現(xiàn)在,將 GraphQL 查詢與我們?yōu)閿?shù)據(jù)定義的聲明式的 React UI 進(jìn)行比較。GraphQL 查詢中的所有內(nèi)容都在 UI 中被用到,UI 中的所有內(nèi)容都會(huì)顯示在 GraphQL 查詢中。

這便是 GraphQL 設(shè)計(jì)哲學(xué)的偉大之處。UI 知道它需要的確切數(shù)據(jù),并且提取出它所要求的數(shù)據(jù)是相當(dāng)容易的。設(shè)計(jì)一個(gè) GraphQL 查詢只需從 UI 中直接提取用作變量的數(shù)據(jù)。

如果我們反轉(zhuǎn)這個(gè)模式,它同樣有效。如果我們有一個(gè) GraphQL 查詢,我們明確知道如何在 UI 中使用它的響應(yīng),因?yàn)椴樵兣c響應(yīng)具有相同的“結(jié)構(gòu)”。我們不需要檢查響應(yīng)才知道如何使用它,我們也不需要有關(guān) API 的任何文檔。這些都是內(nèi)置的。

星球大戰(zhàn)數(shù)據(jù)有一個(gè) GraphQL API 托管在 https://github.com/graphql/swapi-graphql。可以去嘗試使用它構(gòu)建我們的人物數(shù)據(jù)對(duì)象。后續(xù)我們探討的 API 可能會(huì)有一些細(xì)微的變動(dòng),但下面是你可以使用這個(gè) API 來查看我們對(duì)視圖數(shù)據(jù)請(qǐng)求的正式查詢(以Darth Vader為例):

{
  person(personID: 4) {
    name,
    birthYear,
    homeworld {
      name
    },
    filmConnection {
      films {
        title
      }
    }
  }
}

這個(gè)請(qǐng)求定義了一個(gè)非常接近視圖的響應(yīng)結(jié)構(gòu),記住,我們是在一次往返中獲得的所有這些數(shù)據(jù)。

GraphQL 靈活性的代價(jià)

完美的解決方案實(shí)際并不存在。由于 GraphQL 過于靈活,將會(huì)帶來一些明確的問題和擔(dān)憂。

GraphQL 易導(dǎo)致的一個(gè)重要威脅是資源耗盡攻擊(亦稱為拒絕服務(wù)攻擊)。GraphQL 服務(wù)器可能會(huì)受到超復(fù)雜查詢的攻擊,這將耗盡服務(wù)器的所有資源。查詢深度嵌套關(guān)系(用戶 -> 朋友 -> 朋友...),或者使用字段別名多次查詢相同的字段非常容易。資源耗盡攻擊并不是特定于 GraphQL 的場景,但是在使用 GraphQL 時(shí),我們必須格外小心。

我們可以在這里做一些緩和措施。比如,我們可以提前對(duì)查詢進(jìn)行成本分析,并對(duì)可以使用的數(shù)據(jù)量實(shí)施某種限制。我們也可以設(shè)置超時(shí)時(shí)間來終結(jié)需要過長時(shí)間解析的請(qǐng)求。此外,由于 GraphQL 只是一個(gè)解析層,我們可以在 GraphQL 下的更底層處理速率限制。

如果我們?cè)噲D保護(hù)的 GraphQL API 端點(diǎn)并不公開,而是為了供我們自己的客戶端(網(wǎng)絡(luò)或移動(dòng)設(shè)備)內(nèi)部使用,那么我們可以使用白名單方法和預(yù)先批準(zhǔn)服務(wù)器可以執(zhí)行的查詢??蛻舳丝梢砸蠓?wù)器只執(zhí)行使用查詢唯一標(biāo)識(shí)符預(yù)先批準(zhǔn)的查詢。據(jù)說 Facebook 采用的就是這種方法。

認(rèn)證和授權(quán)是在使用 GraphQL 時(shí)需要考慮的其他問題。我們是在 GraphQL 解析過程之前,之后還是之間處理它們?

為了解答這個(gè)問題,你可以將 GraphQL 視為在你自己的后端數(shù)據(jù)獲取邏輯之上的 DSL(領(lǐng)域特定語言)。我們只需把它當(dāng)作可以在客戶端和我們的實(shí)際數(shù)據(jù)服務(wù)(或多個(gè)服務(wù))之間放置的一個(gè)中間層。

然后將認(rèn)證和授權(quán)視為另一層。GraphQL 在實(shí)際的身份驗(yàn)證或授權(quán)邏輯的實(shí)現(xiàn)中并無用處,因?yàn)樗囊饬x并不在于此。但是,如果我們想將這些層放置于 GraphQL 之后,我們可以使用 GraphQL 來傳遞客戶端和強(qiáng)邏輯之間的訪問令牌。這與我們通過 RESTful API 進(jìn)行認(rèn)證和授權(quán)的方式非常相似。

GraphQL 另一項(xiàng)更具挑戰(zhàn)性的任務(wù)是客戶端的數(shù)據(jù)緩存。RESTful API 由于其字典性質(zhì)而更容易緩存。特定地址標(biāo)識(shí)特定數(shù)據(jù)。我們可以使用地址本身作為緩存鍵。

使用 GraphQL,我們可以采取類似的基本方式,將查詢文本用作緩存其響應(yīng)的鍵。但是這種方式有著諸多限制,而且不是很有效率,并且可能導(dǎo)致數(shù)據(jù)一致性的問題。多個(gè) GraphQL 查詢的結(jié)果很容易重疊,而這種基礎(chǔ)的緩存方式無法解決重疊的問題。

對(duì)于這個(gè)問題有一個(gè)很巧妙的解決方案,那就是使用圖查詢表示圖緩存。如果我們將 GraphQL 查詢響應(yīng)范式化為一個(gè)扁平的記錄集合,給每條記錄一個(gè)全局唯一的 ID,那么我們就可以緩存這些記錄,而不是緩存完整的響應(yīng)。

然而這不是一個(gè)簡單的過程。記錄將會(huì)相互引用,我們將在其中管理循環(huán)圖。操作和讀取緩存需要遍歷查詢。盡管我們需要編寫一個(gè)中間層來處理這些緩存邏輯,但是這種方式總體上比基于響應(yīng)的緩存更有效率。Relay.js 便是一個(gè)采用這種緩存策略并在內(nèi)部實(shí)現(xiàn)自動(dòng)管理的框架。

對(duì)于 GraphQL,或許我們應(yīng)該關(guān)心的最重要的問題是通常被稱為 N+1 SQL 查詢的問題。GraphQL 查詢字段被設(shè)計(jì)為獨(dú)立的功能,并且使用數(shù)據(jù)庫中的數(shù)據(jù)解析這些字段可能會(huì)導(dǎo)致對(duì)已解析字段產(chǎn)生新的數(shù)據(jù)庫請(qǐng)求。

對(duì)于簡單的 RESTful API 端點(diǎn)邏輯,可以通過增強(qiáng)結(jié)構(gòu)化的 SQL 查詢來分析,檢測(cè)和解決 N+1 問題。對(duì)于 GraphQL 動(dòng)態(tài)解析的字段,就沒那么簡單了。好在 Facebook 開創(chuàng)了一個(gè)可行的解決方案:DataLoader。

顧名思義,DataLoader 是一個(gè)可用于從數(shù)據(jù)庫讀取數(shù)據(jù)并使其可用于 GraphQL 解析函數(shù)的工具程序。我們可以使用 DataLoader 而不是直接使用 SQL 查詢從數(shù)據(jù)庫中讀取數(shù)據(jù),而 DataLoader 將作為我們的代理,以減少我們發(fā)送到數(shù)據(jù)庫的實(shí)際 SQL 查詢。

DataLoader 的原理是使用批處理和緩存的組合。如果相同的客戶端請(qǐng)求導(dǎo)致需要向數(shù)據(jù)庫請(qǐng)求多個(gè)數(shù)據(jù),則可以使用 DataLoader 來合并這些請(qǐng)求,并從數(shù)據(jù)庫批量加載其響應(yīng)。DataLoader 還將緩存響應(yīng)以使其可用于相同資源的后續(xù)請(qǐng)求。

謝謝閱讀!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88511.html

相關(guān)文章

  • 2017-10-16 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選譯發(fā)布了王躍關(guān)于微信小程序的技術(shù),也許你想錯(cuò)了細(xì)說中的瀏覽器頁面渲染工作原理淺析騰訊前端團(tuán)隊(duì)社區(qū)中文第期安息吧,長存譯借助函數(shù)完成可組合的數(shù)據(jù)類型軟件編寫第十部分掘金對(duì)象與原型掘金技術(shù)周刊期知乎專欄是真正的語言 2017-10-16 前端日?qǐng)?bào) 精選 [譯]Vue 2.5 發(fā)布了王躍:關(guān)于微信小程序的技術(shù),也許你想錯(cuò)了細(xì)說Web API中的Blobchrome瀏覽器頁面渲染工...

    molyzzx 評(píng)論0 收藏0
  • 2017-09-11 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選使用實(shí)現(xiàn)和交互的彈幕效果類型檢測(cè)理解的閉包深入理解之代理和反射,和它們?cè)谥械膬?yōu)先級(jí)中文譯區(qū)塊鏈?zhǔn)侨绾喂ぷ鞯挠醚菔局鯇谧g怎樣處理移動(dòng)端對(duì)圖片資源的限制掘金技術(shù)周刊的正則表達(dá)式掘金開發(fā)環(huán)境搭建掘金與復(fù)雜業(yè)務(wù)組件的 2017-09-11 前端日?qǐng)?bào) 精選 使用canvas實(shí)現(xiàn)和HTML5 video交互的彈幕效果【JS】類型檢測(cè)理解 JavaScript 的閉包深入理解ES6...

    antyiwei 評(píng)論0 收藏0
  • GraphQL:一種更高效、強(qiáng)大和靈活的數(shù)據(jù)提供方式

    摘要:我們知道是一種從服務(wù)器公開數(shù)據(jù)的流行方式。描述所有的可能類型系統(tǒng)基于類型和字段的方式進(jìn)行組織,而非入口端點(diǎn)。因此,需要對(duì)后端進(jìn)行調(diào)整,以滿足新的數(shù)據(jù)需求,這會(huì)降低生產(chǎn)力并顯著降低將用戶反饋集成到產(chǎn)品中的能力。 showImg(https://segmentfault.com/img/remote/1460000017875905?w=2234&h=974); 在前幾天的《StateOf...

    waruqi 評(píng)論0 收藏0
  • GraphQL:一種更高效、強(qiáng)大和靈活的數(shù)據(jù)提供方式

    摘要:我們知道是一種從服務(wù)器公開數(shù)據(jù)的流行方式。描述所有的可能類型系統(tǒng)基于類型和字段的方式進(jìn)行組織,而非入口端點(diǎn)。因此,需要對(duì)后端進(jìn)行調(diào)整,以滿足新的數(shù)據(jù)需求,這會(huì)降低生產(chǎn)力并顯著降低將用戶反饋集成到產(chǎn)品中的能力。 showImg(https://segmentfault.com/img/remote/1460000017875905?w=2234&h=974); 在前幾天的《StateOf...

    zzbo 評(píng)論0 收藏0
  • GraphQL:一種更高效、強(qiáng)大和靈活的數(shù)據(jù)提供方式

    摘要:我們知道是一種從服務(wù)器公開數(shù)據(jù)的流行方式。描述所有的可能類型系統(tǒng)基于類型和字段的方式進(jìn)行組織,而非入口端點(diǎn)。因此,需要對(duì)后端進(jìn)行調(diào)整,以滿足新的數(shù)據(jù)需求,這會(huì)降低生產(chǎn)力并顯著降低將用戶反饋集成到產(chǎn)品中的能力。 showImg(https://segmentfault.com/img/remote/1460000017875905?w=2234&h=974); 在前幾天的《StateOf...

    eccozhou 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Big_fat_cat

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<