日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

干货 | 万字长文全面解析GraphQL,携程微服务背景下的前后端数据交互方案

發(fā)布時間:2025/3/21 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 干货 | 万字长文全面解析GraphQL,携程微服务背景下的前后端数据交互方案 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者簡介

古映杰,攜程研發(fā)高級經理,負責前端框架和基礎設施的設計、研發(fā)與維護。開源項目react-lite和react-imvc作者。

前言

隨著多終端、多平臺、多業(yè)務形態(tài)、多技術選型等各方面的發(fā)展,前后端的數(shù)據(jù)交互,日益復雜。

同一份數(shù)據(jù),可能以多種不同的形態(tài)和結構,在多種場景下被消費。

在理想情況下,這些復雜性可以全部由后端承擔。前端只管從后端接口里,拿到已然整合完善的數(shù)據(jù)。

然而,不管是因為后端的領域模型,還是因為微服務架構。作為前端,我們感受到的是,后端提供的接口,越發(fā)不夠前端友好。我們必須自行組合多個后端接口,才能獲取到完整的數(shù)據(jù)結構。

面向領域模型的后端需求,跟面向頁面呈現(xiàn)的前端需求,出現(xiàn)了不可調和的矛盾。

我們曾經試圖用 RESTful 風格的無線 API 聚合層來解決問題。這一層完全由后端工程師開發(fā)和迭代(前端作為下游等待聚合接口的契約),他們既要理解背后對接的微服務體系,又要理解每個前端頁面的展現(xiàn)需求。

隨著頁面數(shù)量的增加,接口調用方越來越多,后端 API 聚合層的邏輯越來越重。聚合層自身成為新的瓶頸所在。實際情況是,作為中間層的后端,既難以充分對接背后的微服務體系,也難以充分理解前端的頁面展現(xiàn)需求。

他們的整體定位很尷尬,代碼里既有 UI 展示相關的話術等信息,又有大量接口相關的業(yè)務邏輯處理。每次發(fā)布迭代,都要跟上下游做大量的溝通和聯(lián)調。

我們最終意識到,讓最了解頁面數(shù)據(jù)邏輯的前端接管中間層,讓后端回到他們擅長的領域模型,可能是更好的做法。可以減少大家溝通成本,提高前后端的專業(yè)化程度,降低聯(lián)調壓力,加快彼此的開發(fā)效率。

在這種背景下,我們最后選擇使用 Node.js 搭建專門服務于前端頁面呈現(xiàn)的后端,亦即 Backend-For-Frontend,簡稱 BFF。

我們面臨了很多不同的技術選型,主要圍繞在權衡 RESTful API 和 GraphQL。

正如標題所示,我們最終選用的是 GraphQL as BFF。

本文將介紹我們對 GraphQL 所作的考察、探索、權衡、技術選型與設計等多方面的內容,希望能給大家?guī)硪恍﹩l(fā)。

一、GraphQL 模式出現(xiàn)的必然性

面向前端頁面的數(shù)據(jù)聚合層,其接口很容易在迭代過程中,變得愈加復雜;最終發(fā)展成一個超級接口。

它有很多調用方,各種不同的調用場景,甚至多個不同版本的接口并存,同時提供數(shù)據(jù)服務。

所有這些復雜性,都會反映到接口參數(shù)上。

接口調用的場景越多,它對接口參數(shù)結構的表達能力,要求越高。如果只有一個 boolean 類型的參數(shù),只能滿足 true | false 兩種場景罷了。

以產品詳情接口為例,一種很自然的請求參數(shù)結構如下:

里面包含 ChannelCode 渠道信息,IsOp 身份信息,MarketingInfo 營銷相關的信息,PlatformId 平臺信息,QueryNode 查詢的節(jié)點信息,以及 Version 版本信息。最核心的參數(shù) ProductId,被大量場景相關的參數(shù)所圍繞。

審視一下 QueryNode 參數(shù),很容易可以發(fā)現(xiàn),它正是 GraphQL 的雛形。只不過它用的是更復雜的 JSON 來描述查詢字段,而 GraphQL 用更簡潔的查詢語句,完成同樣的目的。

并且,QueryNode 參數(shù),只支持一個層級的字段篩選;而 GraphQL 則支持多層級的篩選。

GraphQL 可以看作是 QueryNode 這種形式的參數(shù)設計的專業(yè)化。相比用 JSON 來描述查詢結果,GraphQL 設計了一個更完整的 DSL,把字段、結構、參數(shù)等,都整合到一起。

仿照格林斯潘第十定律:

任何C或Fortran程序復雜到一定程度之后,都會包含一個臨時開發(fā)的、不合規(guī)范的、充滿程序錯誤的、運行速度很慢的、只有一半功能的Common Lisp實現(xiàn)。

https://zh.wikipedia.org/wiki/%E6%A0%BC%E6%9E%97%E6%96%AF%E6%BD%98%E7%AC%AC%E5%8D%81%E5%AE%9A%E5%BE%8B

或許可以說:

任何接口設計復雜到一定程度后,都會包含一個臨時開發(fā)的、不合規(guī)范的、只有一半功能的 GraphQL 實現(xiàn)。

從 SearchParams, FormData 到 JSON,再到 GraphQL 查詢語句,我們看到不斷有新的數(shù)據(jù)通訊方式出現(xiàn),滿足不同的場景和復雜度的要求。

站在這個層面上看,GraphQL 模式的出現(xiàn),有一定的必然性。

二、GraphQL 語言設計中的必然性

作為一個查詢相關的 DSL,GraphQL 的語言設計,也不是隨意的。

我們可以做一個思想實驗。

假設你是一名架構師,你接到一項任務,設計一門前端友好的查詢語言。要求:

1)查詢語法跟查詢結果相近

2)能精確查詢想要的字段

3)能合并多個請求到一個查詢語句

4)無接口版本管理問題

5)代碼即文檔

我們知道查詢結果是 JSON 數(shù)據(jù)格式。而 JSON 是一個 key-value pair 風格的數(shù)據(jù)表示,因此可以從結果倒推出查詢語句。

上圖是一個查詢結果。很顯然,它的查詢語句不可能包含 value 部分。我們刪去 value 后,它變成下面這樣。

查詢語句跟查詢結果擁有相同的 key 及其層次結構關系。這是我們想要的。

我們可以再進一步,將冗余的雙引號,逗號等部分刪掉。

我們得到了一個精簡的寫法,它已經是一段合法的 GraphQL 查詢語句了。

其中的設計思路和過程是如此簡單直接,很難想象還有別的方案比目前這個更滿足要求。

當然,只有字段和層級,并不足夠。符合這種結構的數(shù)據(jù)太多了,不可能把整個數(shù)據(jù)庫都查詢出來。我們還需要設計參數(shù)傳遞的方式,以便能縮小數(shù)據(jù)范圍。

上圖是一個自然而然的做法。用括號表示函數(shù)調用,里面可以添加參數(shù),可謂經典的設計。

它跟 ES2015 里的 (Method Definitions Shorthand) 也高度相似。如下所示:

前面演示的 GraphQL 參數(shù)寫法,參數(shù)值用的是字面量 userId: 123。這不是一個特別安全的做法,開發(fā)者會在代碼里,用拼接字符串的方式將字面量值注入到查詢語句,也就給了惡意攻擊者注入代碼的機會。

我們需要設計一個參數(shù)變量語法,明確參數(shù)位置和數(shù)量。

我們可以選用 $xxx 這種常見的標記方法,它被很多語言采用來表示變量。沿用這種風格,可以大大減少開發(fā)者的學習成本。

前后端通訊的另一個痛點是,命名。前端經常吐槽后端的字段名過于冗長,或者不知所云,或者拼寫錯誤,或者不符合前端表述習慣。最常見的情況是,后端字段名以大寫字母開頭,而前端習慣 Class 或者 Component 是大寫字母開頭,實例和數(shù)據(jù),則以小寫字母開頭。

我們期望有機會進行字段名調整。

別名映射(Alias)語法,正是為了這個目的而出現(xiàn)的。

上面這種別名映射的語法,在其它語言里也很常見。如果不這樣寫,頂多就是變成:

uid as Uid 或者 uid = Uid 這類做法,差別不大。我認為選用冒號更佳,它跟 ES2015 的解構語法很接近。

至此,我們擁有了 key 層級結構,參數(shù)傳遞,變量寫法,別名映射等語法,可以編寫足夠復雜的查詢語句了。不過,還有幾個小欠缺。

比如對字段的條件表達。假設有兩次查詢,它們唯一的差別就是,一個有 A 字段,另一個沒有 A 字段,其它字段及其結構都是相同的。為了這么小的差別 ,前端難道要編寫兩個查詢語句?

這顯然不現(xiàn)實,我們需要設計一個語法描述和解決這個問題。

它就是——指令(Directive)。

指令,可以對字段做一些額外描述,比如?

@include,是否包含該字段;

@skip,是否不包含該字段;

@deprecate,是否廢棄該字段;

除了上述默認指令外,我們還可以支持自定義指令等功能。

指令的語法設計,在其它語言里也可以找到借鑒目標。Java,Phthon 以及 ESNext 都用了 @ 符號表示注解、裝飾器等特性。

有了指令,我們可以把兩個高度相似的查詢語句,合并到一起,然后通過條件參數(shù)來切換。這是一個不錯的做法。不過,指令是跟著單個字段走的,它不能解決多字段的問題。

比如,字段 A 和字段 B,擁有相同的總體結構,僅僅只有 1 個字段名的差異。前端并不想編寫一樣的 key 值重復多次。

這意味著,我們需要設計一個片段語法(Fragment)。

如上所示,用 fragment 聲明一個片段,然后用三個點表示將片段在某個對象字段里展開。我們可以只編寫一次公共結構,然后輕易地在多個對象字段里復用。

這種設計也是一個經典做法,跟 JavaScript 里的 Spread Properties 很相近。

至此,我們得到了一個相對完整的,對前端友好的查詢語言設計。它幾乎就是 GraphQL 當前的形態(tài)。

如你所見,GraphQL 的查詢語言設計,借鑒了主流開發(fā)語言里的眾多成熟設計。使得任何擁有豐富的編程經驗的開發(fā)者,很容易上手 GraphQL。

按照同樣的要求,重新來一遍,大概率得到跟當前形態(tài)高度接近的設計。這是我理解的 GraphQL 語言設計里包含的必然性。

三、GraphQL 的組成與鏈路

查詢語法,是 GraphQL 面向前端,或者說面向數(shù)據(jù)消費端的部分。

除此之外,GraphQL 還提供了面向后端,或者說面向數(shù)據(jù)提供方的部分。它就是基于 GraphQL 的 Type System 構建的 Schema。

一個 GraphQL 服務和查詢的鏈路,大致如下:

首先,服務端編寫數(shù)據(jù)類型,構建一個數(shù)據(jù)結構之間的關聯(lián)網絡。其中 Query 對象是數(shù)據(jù)消費的入口。所有查詢,都是對 Query 對象下的字段的查詢。可以把 Query 下的字段,理解為一個個 RESTful API。比如上圖中的,Query.post 和 Query.author,相當于 /post 和 /author 接口。

GraphQL Schema 描述了數(shù)據(jù)的類型與結構,但它只是形狀(Shape),它不包含真正的數(shù)據(jù)。我們需要編寫 Resolver 函數(shù),在里面去獲取真正的數(shù)據(jù)。

Resolver 的簡單形式如下

每個 Query 對象下的字段,都有一個取值函數(shù),它能獲取到前端傳遞過來的 query 查詢語句里包含的參數(shù),然后以任意方式獲取數(shù)據(jù)。Resolver 函數(shù)可以是異步的。

有了 Resolver 和 Schema,我們既定義了數(shù)據(jù)的形狀,也定義了數(shù)據(jù)的獲取方式。可以構建一個完整的 GraphQL 服務。

但它們只是類型定義和函數(shù)定義,如果沒有調用函數(shù),就不會產生真正的數(shù)據(jù)交互。

前端傳遞的 query 查詢語句,正是觸發(fā) Resolver 調用的源頭。

如上所示,我們發(fā)起了查詢,傳遞了參數(shù)。GraphQL 會解析我們的查詢語句,然后跟 Schema 進行數(shù)據(jù)形狀的驗證,確保我們查詢的結構是存在的,參數(shù)是足夠的,類型是一致的。任何環(huán)節(jié)出現(xiàn)問題,都將返回錯誤信息。

數(shù)據(jù)形狀驗證通過后,GraphQL 將會根據(jù) query 語句包含的字段結構,一一觸發(fā)對應的 Resolver 函數(shù),獲取查詢結果。也就是說,如果前端沒有查詢某個字段,就不會觸發(fā)該字段對應的 Resolver 函數(shù),也就不會產生對數(shù)據(jù)的獲取行為。

此外,如果 Resolver 返回的數(shù)據(jù),大于 Schema 里描繪的結構;那么多出來的部分將被忽略,不會傳遞給前端。這是一個合理的設計。我們可以通過控制 Schema,來控制前端的數(shù)據(jù)訪問權限,防止意外的將用戶賬號和密碼泄露出去。?

正是如此,GraphQL 服務能實現(xiàn)按需獲取數(shù)據(jù),精確傳遞數(shù)據(jù)。

四、澄清關于 GraphQL 的幾個迷思

有相當多的開發(fā)者,對 GraphQL 有各種各樣的誤解。在這里挑選幾個重要的例子,加以澄清,幫助大家更全面的認識 GraphQL。

4.1 GraphQL 不一定要操作數(shù)據(jù)庫?

有一些開發(fā)者認為 GraphQL 需要操作數(shù)據(jù)庫,因此實現(xiàn)起來,幾乎等于要推翻當前后端的所有架構。這是一個重大誤解。

GraphQL 不僅可以不操作數(shù)據(jù)庫,它甚至可以不從其它地方獲取數(shù)據(jù),而直接寫死數(shù)據(jù)在 Resolver 函數(shù)里。查看 graphql.js 的官方文檔,我們輕易可以找到案例:

上圖定義了一個 schema,只有一個類型為 String 的 hello 字段,它的 resolver 函數(shù)里,無視所有參數(shù),直接 return 一個 hello world 字符串。

可以看到,GraphQL 只是關于 schema 和 resolver 的一一對應和調用,它并未對數(shù)據(jù)的獲取方式和來源等做任何假設。

4.2?GraphQL 跟 RESTful API 不是對立的

在網絡上,有相當多的 GraphQL 文章,將它跟 RESTful API 對立起來,仿佛要么全盤 GraphQL,要么全盤 RESTful API。這也是一個重大誤解。

GraphQL 和 RESTful API 不僅不對立,還是互相協(xié)作的關系。

在前面關于 Resolver 函數(shù)的圖片中,我們看到,可以在 GraphQL Schema 的 Resolver 函數(shù)里,調用 RESTful API 去獲取數(shù)據(jù)。

當然,也可以調用 RPC 或者 ORM 等方式,從別的數(shù)據(jù)接口或者數(shù)據(jù)庫里獲取數(shù)據(jù)。

因此,實現(xiàn)一個 GraphQL 服務,并不需要挑戰(zhàn)當前整個后端體系。它具有高度靈活的適配能力,可以低侵入性的嵌入當前系統(tǒng)中。

4.3?GraphQL 不一定是一個后端服務

盡管絕大多數(shù) GraphQL,都以 server 的形式存在。?但是,GraphQL 作為一門語言,它并沒有限制在后端場景。

上圖還是前面展示過的 graphql.js 的官方文檔,最下面一行,就是一個普通的函數(shù)調用,它發(fā)起了一次 graphql 查詢,其 response 結果如下:

這段代碼,不只能在 node.js 里運行,在瀏覽器里也可以運行(可訪問:https://codesandbox.io/s/hidden-water-zfq2t?查看運行結果)

因此,我們完全可以將 GraphQL 用在純前端,去實現(xiàn) State Management 狀態(tài)管理。Relay 等框架,即包含了用在前端的 graphql。

4.4 GraphQL 不一定需要?Schema

這是一個有趣的事實,GraphQL 語言設計里的兩個組成部分:

1)數(shù)據(jù)提供方編寫 GraphQL Schema;

2)數(shù)據(jù)消費方編寫 GraphQL Query;

這種組合,是官方提供的最佳實踐。但它并不是一個實踐意義上的最低配置。

GraphQL Type System 是一個靜態(tài)的類型系統(tǒng)。我們可以稱之為靜態(tài)類型 GraphQL。此外,社區(qū)還有一種動態(tài)類型的 GraphQL 實踐。

graphql-anywhere: Run a GraphQL query anywhere, without a GraphQL server or a schema.?

https://github.com/apollographql/apollo-client/tree/master/packages/graphql-anywhere

它跟靜態(tài)類型的 GraphQL 差別在于,沒有了基于 Schema 的數(shù)據(jù)形狀驗證階段,而是直接無腦地根據(jù) query 查詢語句里的字段,去觸發(fā) Resolver 函數(shù)。

它也不管 Resolver 函數(shù)返回的數(shù)據(jù)類型對不對,獲取到什么,就是什么。一個字段,不必先定義好,才能被前端消費,它可以動態(tài)的計算出來。

在某些場景下,動態(tài)類型的 GraphQL 有一定的便利性。不過,它同時喪失了 GraphQL 的部分精髓,這塊后面將會詳細描述。

值得一提的是,不管是靜態(tài)類型的 GraphQL 還是動態(tài)類型的 GraphQL,都是既可以運行在服務端,也可以運行在前端。

4.5?GraphQL 不一定返回 JSON?數(shù)據(jù)格式

這是另一個有趣的事實。最初我們演示了,如何基于 JSON 數(shù)據(jù)結果,反推出 GraphQL 查詢語法的設計。而現(xiàn)在,我們卻說 GraphQL 可以不返回 JSON 數(shù)據(jù)格式。

沒錯。當一個新事物出現(xiàn)之后,隨著它的不斷發(fā)展,它可以脫離其初衷,衍生出不同的形態(tài)。

上圖還是來自 graphql-anywhere 里的例子。

在這里,它實現(xiàn)了一個 gqlToReact 的 Resolver,可以把一個 graphql 查詢轉換為 ReactElement 結構。

不只是動態(tài)類型的 GraphQL 有這個能力,靜態(tài)類型的 GraphQL 也有可能實現(xiàn)一樣的效果。

不過這種做法,目前僅僅停留在能力演示階段。其妙用還有待社區(qū)去挖掘和探索。

五、GraphQL 的幾種使用模式

到目前為止,我們見識到了 GraphQL 的高自由度和靈活性。在搭建 GraphQL Server 時,也可以根據(jù)實際需求和場景,采用不同的模式。

5.1 RESTful-Like 模式

這個模式就是簡單粗暴的把 RESTful API 服務,替換成 GraphQL 實現(xiàn)。之前有多少 RESTful 服務,重構后就有多少 GraphQL 服務。它是一個簡單的一對一關系。

默認情況下,面向兩個 GraphQL 服務發(fā)起的查詢是兩次請求,而不是一次。舉個例子:

前端需要產品數(shù)據(jù)時,從之前調用產品相關的 RESTful API,變成查詢產品相關的 GraphQL。不過,需要訂單相關的數(shù)據(jù)時,可能要查詢另一個 GraphQL 服務。

有一些公司拿 GraphQL 小試牛刀時,采取了這個做法;將 GraphQL 用在特定服務里。

不過,這種模式難以發(fā)揮 GraphQL 合并請求和關聯(lián)請求的能力。只是起到了按需查詢,精確查詢字段的作用,價值有限。

因此,他們在實踐后,發(fā)現(xiàn)收效甚微;認為 GraphQL 不過如此,還不如 RESTful API 架構簡單和成熟。

其實這是一種選型上的失誤。

5.2 GraphQL as an API Gateway 模式

在這個模式里,GraphQL 接管了前端的一整塊數(shù)據(jù)查詢需求。

前端不再直接調用具體的 RESTful 等接口,而是通過 GraphQL 去間接獲取產品、訂單、搜索等數(shù)據(jù)。

在 GraphQL 這個中間層里,我們將各個微服務,按照它們的數(shù)據(jù)關聯(lián),整合成一個基于 GraphQL Schema 的數(shù)據(jù)關系網絡。前端可以通過 GraphQL 查詢語句,同時發(fā)起對多個微服務的數(shù)據(jù)的獲取、篩選、裁剪等行為。

值得一提的是,作為 API Gateway 的 GraphQL 服務,可以在其 Resolver 內,向前面提到的 RESTful-like 的 GraphQL 發(fā)起查詢請求。

如此,既避免了前端需要一對多的問題,也解決了 API Gateway GraphQL 需要請求 RESTful 全量數(shù)據(jù)接口的內部冗余問題。讓服務到服務之間的數(shù)據(jù)調用,也可以做到更精確。

GraphQL 服務是一個對數(shù)據(jù)消費方友好的模式。而數(shù)據(jù)消費方,既可以是前端,也可以是其它服務。

當數(shù)據(jù)消費方是其它服務時,通過 GraphQL 查詢語句,彼此之間可以更精確獲取數(shù)據(jù),避免冗余的數(shù)據(jù)傳輸和接口調用。

當數(shù)據(jù)消費方是前端時,由于前端需要跟多個數(shù)據(jù)提供方打交道,如果每個數(shù)據(jù)提供方都是單獨的 GraphQL,那并不能得到本質上的改善。此時若有一個 Gateway 角色的 GraphQL,可以真正減少前端調用的復雜度。

5.2.1 兩類 GraphQL API Gateway 服務

同樣是 API Gateway 角色的 GraphQL 服務,在實現(xiàn)方式上也有不同的分類。

1)包含大量真實的數(shù)據(jù)操作和處理的 GraphQL

2)轉發(fā)數(shù)據(jù)請求,聚合數(shù)據(jù)結果的 GraphQL

第一類,是傳統(tǒng)意義上的后端服務;第二類,則是我們今天的重點,GraphQL as BFF。

這兩類 GraphQL 服務的要求是不同的,前者可能包含大量 CPU 密集的計算,而后者總體而言主要是 Network I/O 相關的行為。

許多公司并不提倡使用 Node.js 構建第一種服務,不管是構建 RESTful 還是 GraphQL。我們也一樣。

因此,后面我們討論的 GraphQL,如果沒有特別聲明,都可以理解為上面所說的第二種類型。

5.3 GraphQL as a Backend Framework

在澄清關于 GraphQL 的迷思時,我們指出,GraphQL 可以不作為 Server。

這意味著,一個包含 GraphQL 實現(xiàn)的 Server,不一定通過 GraphQL 查詢語句進行前后端數(shù)據(jù)交互,它可以繼續(xù)沿用 RESTful API 風格。

也就是說,我們可以把 GraphQL 當作一個服務端開發(fā)框架,然后在 RESTful 的各個接口里,發(fā)起 graphql 查詢。

不管是前端還是其它后端服務,都不必知道 GraphQL 的存在。前端的調用方式,還是 RESTful API,在 RESTful 服務內部,它自己向自己發(fā)起了 GraphQL 查詢。

那么,這個模式有什么好處跟價值?

設想一下,你用 RESTful API 風格實現(xiàn) BFF。由于 PC 端和移動端的場景不同,它們對同一份數(shù)據(jù)的消費方式差異很大。

在 PC 端,它可以一次請求全量數(shù)據(jù)。

在移動端,因為它屏幕小,它要分多次去請求數(shù)據(jù)。首屏一次,非首屏一次,滾動按需加載 N 次,多個 2 級頁面里 M 次。

我們要么實現(xiàn)一個超級接口,根據(jù)請求參數(shù)適配不同場景(即實現(xiàn)一個半吊子的 GraphQL);要么實現(xiàn)多個功能相似,但又不同的 RESTful 接口。

其中的差異太大了,所以很多公司索性就把 BFF 分成,PC-BFF 和 Mobile-BFF 兩個 BFF 服務。

我們可以把 PC-BFF 和 Mobile-BFF 整合成一個 GraphQL-BFF 服務。即便前后端不通過 GraphQL 查詢語句進行交互,我們也可以在各個接口里,編寫相對簡單的查詢語句,代替更高成本的接口實現(xiàn)。

也即是說,使用 GraphQL 搭建 BFF,如果出現(xiàn)前后端分工、溝通等方面的矛盾。我們可以將 GraphQL 服務降級為 RESTful 服務,無非就是把需要前端編寫的查詢語句,寫死在后端接口里面罷了。

如果實現(xiàn)的是 RESTful 服務,要轉換成 GraphQL 服務,就沒有那么簡單了。

有了這種優(yōu)雅降級的能力,我們可以更加放心大膽的推動 GraphQL-BFF 方案。

六、GraphQL 精髓

理解 GraphQL 的精髓所在,可以幫助我們更正確地實踐 GraphQL。

首先來想一下,GraphQL 為什么要叫 GraphQL,其中的 Graph 體現(xiàn)在什么地方?

GraphQL 的查詢語句,看起來是 JSON 寫法的一種簡化。而 JSON 是一個 Tree 樹形數(shù)據(jù)結構。為什么不叫 TreeQL,而是 GraphQL 呢?

6.1?Tree VS Graph

一個重要的前置知識是,什么是 Tree,什么是 Graph,它們有什么關系?

下圖是一個 Tree 的結構示意圖。

Tree 有且只有一個 Root 節(jié)點,并且對于每個非 Root 節(jié)點,有且只有一個父節(jié)點;它們組成了一個層次結構。其中任意兩個節(jié)點,有且只有一條連接路徑;沒有循環(huán),也沒有遞歸引用。

下圖是一個 Graph 的結構示意圖。

而 Graph 里的節(jié)點之間,可能存在不只一種連接路徑,可能存在循環(huán),可能存在遞歸引用,可能沒有 Root 節(jié)點。它們組成了一個網絡結構。

我們可以把 Graph 這種網絡結構,通過裁剪連接路徑,把它壓縮成任意節(jié)點只有唯一連接路徑的簡化形態(tài)。如此網絡結構退化成層次結構,它變成了 Tree。

也就是說,Graph 是比 Tree 更復雜的數(shù)據(jù)結構,后者是它的簡化形式。擁有 Graph,我們可以按照不同的裁剪方式,衍生出不同的 Tree。而 Tree 里包含的信息,如果不增加其它額外數(shù)據(jù),不足以構建足夠復雜的 Graph 結構。

6.2?GraphQL 里的 Graph 結構

在 GraphQL 里,承擔構建網絡結構的,并非 GraphQL 查詢語句,而是基于 GraphQL Type System 構建的 Schema。

上圖是一個 GraphQL Schema,定義了 A, B, C, D 和 E 五種數(shù)據(jù)類型,它們分別掛載到?入口類型 Query 里的 a, b, c, d 和 e 字段里。

A, B, C, D, E 里面,包含著遞歸的結構。A 里面包含 B 和 C,B 里面包含 C 和 D,D 里面包含 E,E 里面又包含 A,又回到了 A。

這是一個復雜的關系網絡。要構建遞歸關聯(lián),并不需要這么復雜。直接 A 里包含 B,和 B 里包含 A 也行,此處是一個演示。

有了這個基于數(shù)據(jù)類型的 Graph 關系網絡,我們可以實現(xiàn)從 Graph 中派生出 JSON Tree 的能力。

上圖是一個 GraphQL 的查詢語句,它是一個包含很多 key 的層次結構,亦即一個 Tree。

它從根節(jié)點里取 a 字段,然后向下分層,找到了 e。而 e 節(jié)點里也包含一個跟根節(jié)點同類型的 a 字段,因此它可以繼續(xù)向下分層,重來一遍,又到了 e 節(jié)點,此時它只取了 data 字段,查詢中止。

我編寫了一個簡單的 Resolver 函數(shù),用來演示查詢結果。

它很簡單。Query 里返回跟字段名一樣的字母,任何子節(jié)點的數(shù)據(jù),都是拼接父節(jié)點的字母串。如此我們可以從查詢結果看出數(shù)據(jù)流動的層次。

查詢結果如下:

第一個 e 節(jié)點的 data 字段里,拿到了父節(jié)點里的 data 數(shù)據(jù),其父節(jié)點的 data 數(shù)據(jù)又是通過它的父節(jié)點里獲取的,因此有一個數(shù)據(jù)鏈條。

而第二個 e 節(jié)點同理,它有兩段鏈條。

只要不編寫后續(xù)字段,我們可以停留在任意節(jié)點的 data 字段里。

也就是說,我們用作為 Tree 的 Query 語句,去裁剪了作為 Graph 的 Schema 數(shù)據(jù)關聯(lián)網絡,得到了我們想要的 JSON 結構。

通過這個角度,我們可以理解為什么 GraphQL 不允許 Query 語句停留在 Object 類型,一定要明確的寫出對象內部的字段,直到所有 Leaf Node 都是 Scalar 類型。

這不僅僅是一個所謂的最佳實踐,這也是 Graph 本身的特征。對象節(jié)點里,可能通過循環(huán)或者遞歸關系,拓展出無限大的數(shù)據(jù)結構。Query 語句必須寫清楚,才能幫助 GraphQL 去裁剪掉不必要的數(shù)據(jù)關聯(lián)路徑。

6.3?Graph 網絡結構的實際價值

前面的 A, B, C, D, E 案例,并不能直觀的讓大家感受到,Graph 網絡結構的實際價值。它看起來像一個連線游戲。

放到 Facebook 的社交網絡場景下,其必要性和價值就凸顯了。

假設我們要一次性獲取用戶的好友的好友的好友的好友的好友,基于 RESTful API 我們有什么特別好的方法嗎?很難說。

而 Graph 這種遞歸關聯(lián)的結構,實現(xiàn)這種查詢輕而易舉。

我們定義了一個 User 類型,掛到 Query 入口上的 user 字段里。User 類型的 friends 字段又是一個 User 類型的列表。這樣就構建了一個遞歸關聯(lián)。

getFriends 查詢語句,可以不斷地從任意用戶開始,關聯(lián)其 friends,得到 friends 數(shù)組結果。任意一個 friend 也是 User,它也有自己的 friends。查詢語句在最外層的 friends 停了下來,它只查詢了 id 和 name 字段。

看到這里,另一個經典的關于 GraphQL 的誤解出現(xiàn)了:只有像 Facebook,Twitter 這類社交關系網絡,才適合 GraphQL,而我們的場景下,GraphQL 并不適用。

其實不然,社交關系網絡里使用 GraphQL 特別有效,不意味著其它場景下,GraphQL 不能帶來收益。

設想一個電商平臺的場景,它有用戶、產品和訂單這組鐵三角,其它庫存、價格,優(yōu)惠券,收藏等先不提。在最簡單的場景下,GraphQL 依然可以發(fā)揮作用。

我們構建了 User,Product 和 Order 三個類型,它們彼此之間有字段上的遞歸關聯(lián)關系,是一個 Graph 結構。在 Query 入口類型上,分別有 user, product 和 order 三個字段。

據(jù)此,我們可以實現(xiàn)從 user, product 和 order 任意維度出發(fā),通過它們的關聯(lián)關系,實現(xiàn)豐富而靈活的查詢。

比如,查看用戶的所有訂單及其跟訂單相關的產品,Query 語句如下:

我們查詢了 id 為 123 的用戶,他的名字和訂單列表,對于每個訂單,我們獲取該訂單的創(chuàng)建時間,購買價格和關聯(lián)產品,對于訂單關聯(lián)的產品,我們獲取了產品 id,產品標題,產品描述和產品價格。

當我們的后端人員組織架構是按照領域模型來劃分時,用戶,產品和訂單,通常是 3 個團隊,他們各自提供領域相關的接口。通過 GraphQL 我們可以很容易將它們整合到一起。

再比如,查看一個產品下的所有訂單及其關聯(lián)用戶,Query 語句如下:

我們查詢了 id 為 123 的產品,它的產品標題,產品描述和價格,以及關聯(lián)的訂單。對于每個關聯(lián)訂單,我們查詢了訂單的創(chuàng)建時間,購買價格以及下訂單的用戶,對于下訂單的用戶,我們查詢了他的用戶 id 和名稱。

如你所見,只要構建出了 Graph 結構的數(shù)據(jù)網絡,它不像 Tree 那樣有唯一的 Root 節(jié)點。從任意入口出發(fā),它都可以通過關聯(lián)路徑,不斷的衍生出數(shù)據(jù),得到 JSON 結果。

我們不必疲于編寫面向產品詳情頁的接口,面向訂單詳情頁的接口,面向用戶信息的接口。我們編寫了一個數(shù)據(jù)關系網絡,就足以適配不同的場景。

此處演示的,只是用戶,產品和訂單這三個資源的關系網絡,已經可以看出 GraphQL 的適用性。在實際場景中,我們能搭建出更復雜的數(shù)據(jù)網絡,它具備更強大的數(shù)據(jù)表達能力,可以給我們的業(yè)務帶來更多收益。

七、我們的 GraphQL-BFF 實踐模式

在掌握上述關于 GraphQL 的綱領知識后,我們來看一下在實踐中 ,GraphQL-BFF 的一種實際做法。

首先是技術選型,我們主要采用了如下技術棧。

開發(fā)語言選用了 TypeScript,跑在 Node.js v10.x 版本上,服務端框架是 Koa v2.x 版本,使用 apollo-server-koa 模塊去運行 GraphQL 服務。

Apollo-GraphQL 是 Node.js 社區(qū)里,比較知名和成熟的 GraphQL 框架。做了很多的細節(jié)工作,也有一些相對前沿的探索,比如 Apollo Federation 架構等。

不過,有兩點值得一提:

1)Apollo-GraphQL 屬于 GraphQL 社區(qū)的一部分,而非 Facebook 官方的 GraphQL 開發(fā)團隊。Apollo-GraphQL 在官方 GraphQL 的基礎上進行了帶有他們自身理念特點的封裝和設計。像 Apollo Federation 這類目前看來比較激進的方案,即使是 GraphQL 官方的開發(fā)人員,對此也持保留態(tài)度。

2)Apollo-GraphQL 的重心是前文所說的第一類 API Gateway 角色的 GraphQL 服務,本文探討的是第二類。因此,Apollo-GraphQL 里有很多功能對我們來說沒必要,有一些功能的使用方式,跟我們的場景也不契合。

我們主要使用的是 Apollo-GraphQL 的 graphql-tools 和 apollo-server-koa 兩個模塊,并在此基礎上,進行了符合我們場景的設計和改編。

7.1?我們的 GraphQL-BFF 架構設計

GraphQL-BFF 的核心思路是,將多個 services 整合成一個中心化 data graph。

每個 service 的數(shù)據(jù)結構契約,都放入了一個大而全的 GraphQL Schema 里;如果不做任何模塊化和解耦,開發(fā)體驗將會非常糟糕。每個團隊成員,都去修改同一份 Schema 文件。

這明顯是不合理的。GraphQL-BFF 的開發(fā)模式,應該跟 service 的領域模型,有一一對應的關系。然后通過某種形式,多個 services 自然整合到一起。

因此,我們設計了 GraphQL-Service 的概念。

7.1.1?GraphQL-Service

GraphQL-Service 是一個由 Schema + Resolver 兩部分組成的 JS 模塊,它對應基于領域模型的后端的某個 Servcie。每個 GraphQL-Service 應該可以按照模塊化的方式編寫,跟其它 GraphQL-Service 組合起來后,構建出更大的 GraphQL-Server。

GraphQL-Service 通過 GraphQL 的 Type Extensions 構建數(shù)據(jù)關聯(lián)關系。

如上所示,我們的 UserService 里面,只涉及到了 User 相關的類型處理。它定義了自己的基本字段,id 和 name。通過 extend type 定義了它在 Order 和 Product 數(shù)據(jù)里的關聯(lián)字段,以及定義在 Query 里的入口字段。

從 User Schema 里我們可以看到,User 有兩類查詢路徑。

1)通過根節(jié)點 Query 以傳遞參數(shù)的方式,獲取到 User 信息。

2)通過 Product 或 Order 節(jié)點,以數(shù)據(jù)關聯(lián)的方式,獲取到 User 信息。

上圖是 OrderService 的 Schema,它也只涉及了 Order 相關的類型邏輯。同樣是通過 extend type 定義了在 User 和 Product 里的關聯(lián)字段,以及定義了在根節(jié)點 Query 里的入口字段。

Order 數(shù)據(jù)跟 User 一樣,有兩種消費路徑。一種通過 Query 節(jié)點,另一種是通過數(shù)據(jù)關聯(lián)節(jié)點。

前面我們演示 User, Order 和 Product 鐵三角關系時,是在同一個 Schema 里編寫它們的關聯(lián)。我們把多個 GraphQL-Service 的 Schema 整合到一起后,可以生成同樣的結果:

上圖不是我們手動編寫的,而是 merge 多個 GraphQL-Service 的 Schema 后生成的結果。可以看出來,跟之前手寫的版本,總體上是一樣的。

有了解耦的 Schema 并不足夠,它只定義了數(shù)據(jù)類型及其關聯(lián)。我們需要 Resolver 去定義數(shù)據(jù)的具體獲取方式,Resolver 也需要解耦。

7.1.2?GraphQL-Resolver

不管是在官方的 GraphQL 文檔里,還是 Apollo-GraphQL 的文檔里,Resolver 都是以普通函數(shù)的形態(tài)出現(xiàn)。

這在簡單場景下,沒有什么問題。正如在簡單場景下,用 node.js 的 http.createServer 就可以創(chuàng)建一個 server。

如上,設置狀態(tài)碼,設置響應的 Content-Type,返回內容即可。

然而,在更復雜的真實項目中,我們實際上需要 express、koa 等服務端框架,用中間件的模式編寫我們的服務端處理邏輯,由框架將它們整合為一個requestListener 函數(shù),注冊到 http.createServer(requestListener) 里。

在 GraphQL Server 里,雖然 endpoint 只有 /graphql 一個,但不代表它只需要一組 Koa 中間件。

正如一開始我們指出的,每個超級接口里都包含一半功能的 GraphQL 實現(xiàn)。GraphQL 是往超級接口的方向更進一步,不能簡單地以普通接口的眼光去看待它。

在 Query 下的每個字段,都可能對應 1 到多個內部服務的 API 的調用和處理。只用普通函數(shù)構成的 resolverMap,不足以充分表達其中的邏輯復雜度。

不管是用 endpoint 來表示資源,還是用 GraphQL Field 字段來表示資源,它們只是外在形式略有不同,不會改變業(yè)務邏輯的復雜度。

因此,采用比普通函數(shù)具有更好的表達能力的中間件,組合出一個個 Resolver,再整合到一個 ResolverMap 里。可以更好的解決之前解決不了,或者很難的問題。

所謂的架構能力,體現(xiàn)在理解我們面對的問題的復雜度及其本質特征,并能選擇和設計出合適的程序表達模型。

后面我們將演示,正確的架構,如何輕易地克服之前難以解決的問題。

7.1.3?用 koa-compose 組織我們的 Resolver

或許很多同學并不清楚,express 或 koa 里的中間件模式,可以脫離作為服務端框架的它們而單獨使用。正如 GraphQL 可以單獨不作為 server,在任意支持 JavaScript 運行的地方使用一樣。

我們將使用 koa-compose 這個 npm 模塊,去構造我們的 Resolver。

前文里提到的 gql 函數(shù),接受一個 Schema 返回一個 GraphQL-Service,每個 GraphQL-Service 都有一個 resolve 方法:

resolve 方法,接受兩個參數(shù)。第一個是 typeName,對應 GraphQL-Schema 里的 Object Type 的類型名稱;第二個是 fieldHandlers,每個 handler 支持中間件模式,最終它們將被 koa-compose 整合成一個 Resolver。

以 UserService 為例,其 Resolver 寫起來如下:

作為普通函數(shù)的 Resolver 接收的所有參數(shù),都被整合到了 ctx 里面。ctx.result 則是該字段的最終輸出,類似于 koa server 里的 ctx.body。我們刻意采用了 ctx.result 這個不同于 ctx.body 的屬性,明確區(qū)分我們處理的是一個接口還是一個字段。

在簡單場景下,中間件模式的 Resolver 跟普通函數(shù)的 Resolver,僅僅是參數(shù)的數(shù)量和返回值的方式不同。并不會增加大量的代碼復雜度。

當我們多個字段要復用相同的邏輯時,編寫成中間件,然后將 handler 變成數(shù)組形式即可。(在代碼里我們用 json 模擬了數(shù)據(jù)庫表,所以是同步代碼,實際項目里,它可以是異步的調用接口或者查詢數(shù)據(jù)庫)。

上面的 logger,只是一個簡單案例。除此之外,我們可以編寫 requireLogin 中間件,決定一個字段是否只對登陸用戶可用。我們可以編寫不同的工具型中間件,注入 ctx.fetch, ctx.post, ctx.xxx 等方法,以供后續(xù)中間件使用。

每個 GraphQL Field 字段,都擁有獨立的一組中間件和 ctx 對象,跟其他字段互相不影響。我們同時,可以把所有字段共享的中間件,放到 koa server 里的中間件里。

如上圖所示,綠框是 endpoint,可以編寫 koa server 層面的 middleware。而藍框是 GraphQL Field 字段,可以編寫 Resolver 層面的 middleware。endpoint 層面的 middleware 對 ctx 的修改,會影響到后面所有字段。

也就是說,我們可以像上面那樣。掛接口層面的 logger,可以知道整個 graphql 查詢的耗時。編寫一個中間件,在 next 之前,掛載一些方法,供后續(xù)中間件使用;在 next 之后,拿到 graphql 的查詢結果,進行額外的處理。

7.2?解決 mock 難題

GraphQL 是天生 mock 友好的模式,因為其 Schema 里已經指明了所有數(shù)據(jù)的類型及其關聯(lián);很容易可以通過 faker data 之類的手段,自動根據(jù)類型生成假數(shù)據(jù)。

然而,在實踐中,實現(xiàn) GraphQL Mocking 還是有不少的挑戰(zhàn)。

如上圖所示,在 Apollo GraphQL 里,mock 看似很簡單,只需要在創(chuàng)建服務時,設置 mock 為 true,或者提供一個 mock resolver 即可。但是,一個全局的,跟著服務創(chuàng)建走的 mock,太過粗暴。

mock 的價值在于提供更好的數(shù)據(jù)靈活性以加速開發(fā)效率。它既可以在沒有數(shù)據(jù)時,提供假數(shù)據(jù);也可以在真數(shù)據(jù)的接口有問題時,不用重啟服務,也能降級為假數(shù)據(jù)。它既可以是整個 GraphQL 查詢級別的 mock,也可以是字段級別的 mock。

作為超級接口的 GraphQL 服務,全局的,在啟動階段就固化的 mocking,意義不大。

Apollo GraphQL 的 mocking 實踐問題,正是它采用普通函數(shù)來描述 Resolver 所帶來的;它很難簡單的通過拓展某個 resolver 而支持 mocking。它不得不在創(chuàng)建服務時,額外新增一個 mock resolver map 去承擔 mocking 職能。

而我們的 composed resolver 處理動態(tài) mocking 卻異常簡單。

它不僅可以在運行時動態(tài)確定,它不僅可以細化到字段級別,它甚至可以跟著某次查詢走 mock 邏輯(通過添加 @mock 指令)。

上圖是默認情況下,基于 faker 這個 npm 包,根據(jù)數(shù)據(jù)類型生成的 mock data。

在我們的設計里,默認的 mocking,其內部實現(xiàn)方式很簡單。我們先是編寫了上圖,根據(jù) GraphQL Type 調用 faker 模塊對應的方法,生成假數(shù)據(jù)。

然后在 createResolver 這個將中間件整合成 resolver 的函數(shù)里,先判斷中間件里是否存在自定義的 mock handler 函數(shù),如果沒有,就追加前面編寫的 mocker 處理函數(shù)。

我們還提供了 mock 中間件,讓開發(fā)者能指定 mock 數(shù)據(jù)來源,比如指定 mock json 文件。

mock 中間件,接收字符串參數(shù)時,它會搜尋本地的 mock 目錄下是否有同名文件,作為當前字段的返回值。它也接收函數(shù)作為參數(shù),在該函數(shù)里,我們可以手動編寫更復雜的 mock 數(shù)據(jù)邏輯。

有趣的地方是,mock/user.json 文件里,只包含上圖紅框的數(shù)據(jù),其關聯(lián)出來的 collections 字段,是真實的。這是合理的做法,mock 應該跟著 resolver 走。關聯(lián)字段擁有自己的 resolver,可能調用自己的接口;不應該因為父節(jié)點是 mock 的,子節(jié)點也進入 mock 模式。

如此,我們可以在父節(jié)點 resolver 對應的后端接口掛掉后,mock 它,讓沒掛掉的子節(jié)點 resolver 正常運行。如果我們希望子節(jié)點 resolver 也進入 mock。很簡單,添加一個 @mock 指令即可。

如上所示,user 字段和 collections 字段的 resolver 都進入了 mock 模式。

自定義 mock resolver 函數(shù)的方式如上圖所示,mock 中間件保證了,只有在該字段進入 mock 模式時,才執(zhí)行 mock resolver function。并且,mock resolver function 內部依然有機會通過調用 next 函數(shù),觸發(fā)后面的真實數(shù)據(jù)獲取邏輯。

以上所有這些靈活性,都來自于我們選用了表達能力和可組合性更好的中間件模式,代替普通該函數(shù),承擔 resolver 的職能。

總結

至此,我們得到了一個簡單而靈活的實踐模式。我們用 Schema 去構建 Data Graph 數(shù)據(jù)關聯(lián)圖,我們用 Middleware 去構建 Resolver Map,它們都具備很強的表達能力。

在開發(fā) GraphQL-BFF 時,我們的 GraphQL-Service 跟后端基于領域模型的 Service,具有總體上的一一對應關系。不會產生后端數(shù)據(jù)層解耦后,在 GraphQL 層重新耦合的尷尬現(xiàn)象。

關于 GraphQL 還有很多話題可以討論,比如 batching , caching 等。這部分內容在網絡上很多 GraphQL 的文檔和教程里都可以找到,這里我們不再贅述。

總的而言,根據(jù)我們對 GraphQL 的考察和實踐,我們認為它可以比 RESTful API 更好的解決我們面對的問題。

我們對 GraphQL 的期望,不僅僅停留在 BFF 層。我們希望通過積累在 BFF 層使用 GraphQL 的成功經驗,幫助我們摸索出在 Micro Frontend 架構上使用 GraphQL 模式的合理設計。

如前面所演示的,像 User,Product 和 Order 這種公共級別的數(shù)據(jù)類型,不可能只由一個團隊去維護,它們需要被其它團隊所拓展。使得我們可以通過用戶,找到它關聯(lián)的訂單,收藏,優(yōu)惠券等由其它團隊維護的數(shù)據(jù)。

放到 Micro Frontend 架構上,一個支付按鈕,也夾雜了多種類型的數(shù)據(jù),產品信息,用戶信息,庫存信息,UI 展示信息,交互狀態(tài)信息等等,綜合了這些信息,支付按鈕被點擊時,才得到了充分的數(shù)據(jù),可以決定是否去支付。

樸素 Micro Frontend 的設計,用 Vue, React, Angular 不同框架,分別維護不同組件,通過 router/message-passing 等方式互相通訊。在我看來,這是對后端微服務架構的拙劣模仿。

后端服務,各自部署在獨立環(huán)境中,對體積不敏感;因而可以采用不同的語言和技術棧。這不意味著將它簡單的放到前端里一樣成立。無法共享前端開發(fā)的基礎設施,這不是微前端,這是一種人員組織架構上的混亂。

GraphQL 讓我們看到,基于領域模型的微前端架構,可能是更好的方向。一個簡單的支付按鈕,也綜合了多個領域模型,由多個開發(fā)者有組織的協(xié)同開發(fā)。并不因為它表面上看起來是一個 Button 組件,就由某個團隊單獨維護。

當然,探索 GraphQL 的其它方向的前提是,GraphQL-BFF 架構得到成功的驗證。就現(xiàn)階段的實踐成果來看,我們對此充滿了信心。

盡管我們的代碼暫無開源計劃,不過相信這篇文章,足夠完整和清楚地介紹了我們的 GraphQL-BFF 方案。希望它能給大家?guī)硪稽c幫助。

總結

以上是生活随笔為你收集整理的干货 | 万字长文全面解析GraphQL,携程微服务背景下的前后端数据交互方案的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

毛片随便看 | 91福利影院在线观看 | 99热这里是精品 | 狠狠狠狠狠狠狠 | 婷婷六月网 | 在线成人一区 | 99精品一区二区三区 | 在线直播av | 欧美男女爱爱视频 | www亚洲国产| 国产一区二区久久久久 | 香蕉影院在线观看 | 亚洲日本精品 | 天天鲁一鲁摸一摸爽一爽 | 青青啪 | 日韩偷拍精品 | 午夜少妇一区二区三区 | 亚洲精品成人免费 | 久久久久麻豆v国产 | 免费看污污视频的网站 | 99久久精品久久久久久动态片 | av中文字幕不卡 | 国产精品免费观看视频 | 久久精品8 | av免费观看网址 | 亚洲h在线播放在线观看h | 91在线国内视频 | 男女视频久久久 | 日韩电影中文 | 丁香资源影视免费观看 | 91完整视频| 亚洲激情国产精品 | 亚洲最大在线视频 | 狠狠狠干 | 91人人在线| 精品人人人人 | 欧美a性| 久草在线最新视频 | 97精品一区二区三区 | 波多野结衣在线视频一区 | 精品久久国产精品 | 久草在线视频看看 | 天天se天天cao天天干 | 午夜婷婷在线观看 | 超碰97公开 | 国产精品日韩在线播放 | 国产精品欧美激情在线观看 | 在线播放 日韩专区 | 99久久久国产精品免费观看 | 久久y | 97av影院| 午夜丰满寂寞少妇精品 | 久久tv| 久久视频一区二区 | 欧美激情奇米色 | 欧美精品久久久久久久久久 | 一区二区三区手机在线观看 | 成人免费大片黄在线播放 | 国产99久久久久久免费看 | 99亚洲精品视频 | 国内精品久久久久久久 | 91麻豆精品 | 高清精品久久 | 国产美女视频免费 | 国产只有精品 | 这里只有精品视频在线观看 | 天天色婷婷 | 国产一区在线观看视频 | 五月婷婷在线视频观看 | 国产精品九九九九九 | 性色在线视频 | 天天干视频在线 | 久久久久久久久久久久久久av | 久草在线视频在线观看 | 亚洲精品男女 | 99久久国产免费,99久久国产免费大片 | 精品国产欧美一区二区三区不卡 | 日本黄色a级大片 | 成人免费在线视频观看 | 亚洲天堂在线观看完整版 | 亚洲专区视频在线观看 | 九色琪琪久久综合网天天 | 岛国片在线 | 日韩精品在线观看视频 | 婷色| 成人久久久久久久久久 | 欧美精品久久天天躁 | 欧美日韩国产高清视频 | 天天操天天干天天操天天干 | 日韩中文字幕亚洲一区二区va在线 | 中文字幕日本电影 | 日韩毛片在线免费观看 | 精品国产成人av在线免 | 亚洲综合日韩在线 | 中文字幕高清在线 | 96国产精品视频 | 国产中文字幕视频在线观看 | 国产一及片 | 久久久免费观看视频 | 在线观看黄av | 久久精品精品电影网 | 麻豆精品传媒视频 | 香蕉91视频 | av电影在线观看完整版一区二区 | 蜜臀av免费一区二区三区 | 免费日韩一区二区三区 | 国产在线观看网站 | 99婷婷狠狠成为人免费视频 | 日韩精品一区二区三区在线视频 | 午夜视频导航 | 午夜视频日本 | 91久久国产自产拍夜夜嗨 | 摸阴视频| 免费观看日韩 | 99久久999久久久精玫瑰 | 亚洲h色精品 | 国产精品久久久久久久久搜平片 | 亚洲精品国产精品乱码不99热 | 欧美va天堂va视频va在线 | 亚洲第一伊人 | 国产精品网红直播 | 国产精品99免视看9 国产精品毛片一区视频 | 日韩精品中文字幕一区二区 | 色在线高清 | 国产精品久免费的黄网站 | 久久视频| 亚洲一级片 | 色综合亚洲精品激情狠狠 | 亚洲高清视频在线 | 啪啪免费试看 | 亚洲成人家庭影院 | 久青草视频在线观看 | 欧美成人影音 | 欧美精选一区二区三区 | av成人黄色| 亚洲电影久久 | 1024久久 | 五月开心六月婷婷 | 97av.com| 草免费视频 | 香蕉视频在线免费看 | 手机在线日韩视频 | 欧美性生活免费 | 久久久久久久久久久成人 | 综合网色 | 国产成人在线网站 | 国产精品久久99综合免费观看尤物 | 日韩精品一区二区三区第95 | 久草在线免费资源站 | 欧美色婷| 在线国产视频一区 | 国产精品淫 | 国产理论片在线观看 | av中文在线 | 九九热.com| 国产不卡在线看 | 麻豆传媒视频在线播放 | www.天天操 | 国产午夜在线观看 | 91福利小视频 | 婷婷色综合色 | 久久av在线 | 四虎影视国产精品免费久久 | 国产精品久久久久久久久久久杏吧 | 色婷在线 | 国产一线二线三线在线观看 | 天天爱天天射天天干天天 | 久久无码精品一区二区三区 | 亚洲一区二区视频在线播放 | 亚洲爱爱视频 | www.夜夜| 国产一区二区在线观看视频 | 色网址99 | 福利一区在线 | 午夜精品视频在线 | 久久久久国产一区二区三区 | 久久久久久久福利 | 四虎免费在线观看视频 | 亚洲黄色在线播放 | 中文字幕在线一区观看 | 天天搞天天干 | 999久久a精品合区久久久 | 欧美性色xo影院 | 99精品久久久久 | 999久久久久 | 亚洲精品国产综合99久久夜夜嗨 | 亚洲精品视频国产 | 精油按摩av | 精品国产乱码久久久久久1区二区 | 成人网在线免费视频 | 欧美一区二区在线 | 黄色成人小视频 | 国产 欧美 在线 | 精品国产乱码久久久久 | 亚洲在线观看av | 中国美女一级看片 | 亚洲精品在线免费观看视频 | 国产精品av免费在线观看 | 91精品免费 | 五月天综合色激情 | 青青草国产成人99久久 | 亚洲精品国久久99热 | 国产精品美 | 免费日韩一区二区三区 | 亚洲高清国产视频 | 一二三区高清 | 国产一级片在线播放 | 欧美极品xxx| 国产精品久久久久久久久久久免费看 | a天堂最新版中文在线地址 久久99久久精品国产 | 久久草网 | 婷婷激情欧美 | 国产色婷婷精品综合在线手机播放 | 日韩色中色 | 国产 中文 日韩 欧美 | 偷拍精偷拍精品欧洲亚洲网站 | 在线视频欧美日韩 | 天天插天天狠天天透 | av网址最新 | 91伊人| 97色视频在线 | 91系列在线 | 国产精品乱码高清在线看 | 欧美精品中文 | 久草在 | 五月婷婷黄色网 | 婷婷看片| 亚洲精品综合在线 | 综合国产在线观看 | 手机色站| 日韩欧美视频在线播放 | 国产在线精品国自产拍影院 | 午夜影视av | 青青久草在线视频 | 久久午夜网 | 国产伦精品一区二区三区在线 | 欧美a免费| 欧美天天综合网 | 五月婷婷另类国产 | 在线视频a | 丁香六月色| 久久成熟 | 免费在线观看av不卡 | 久久久久久免费毛片精品 | 五月婷婷丁香 | 欧美日韩一区二区久久 | 成人影视免费看 | 国产三级久久久 | 亚洲永久国产精品 | 丝袜+亚洲+另类+欧美+变态 | 婷婷六月久久 | 四虎亚洲精品 | 制服丝袜欧美 | 麻豆视频免费在线观看 | 一个色综合网站 | 久草在线中文888 | 人人插人人射 | 色婷婷亚洲 | 国产黑丝袜在线 | 国产精品二区在线 | 色在线高清 | 人人爽久久久噜噜噜电影 | 欧美大片aaa| 亚洲va综合va国产va中文 | 亚洲国产成人精品在线观看 | 91重口视频 | 视频在线在亚洲 | 国产91电影在线观看 | 亚洲一区精品人人爽人人躁 | 黄色大片免费网站 | 18久久久久 | japanese黑人亚洲人4k | 日韩高清观看 | 亚洲乱码国产乱码精品天美传媒 | 日韩精品中文字幕在线不卡尤物 | 天天爱综合 | 国产日韩欧美在线一区 | 丁香综合激情 | 免费看片网址 | av电影在线观看完整版一区二区 | 亚洲一区黄色 | 天天爱天天草 | 国产v视频| 碰超在线观看 | 国产99久久久国产精品免费看 | 精品国产亚洲日本 | 国产高清视频免费在线观看 | 手机在线黄色网址 | 亚洲一区二区三区91 | 五月天中文在线 | 中文字幕成人在线 | 视频高清 | 日韩免费在线一区 | 日日天天狠狠 | 美女在线国产 | 国产在线视频资源 | 国产97在线播放 | 亚洲视频 一区 | 黄色国产高清 | 在线播放 一区 | 国产黄视频在线观看 | 99草在线视频 | 国产又粗又猛又黄又爽 | 国产高清av | 制服丝袜在线91 | 欧美日韩三级在线观看 | 欧美日韩国产一区 | 在线观看视频你懂的 | 一级片在线 | av福利免费 | 日日干美女 | 一级特黄av | 激情视频一区二区三区 | 欧美精品xxx | 9在线观看免费高清完整 | 成人91av | 成人av久久 | 日本丰满少妇免费一区 | 91麻豆精品91久久久久同性 | 国产福利91精品张津瑜 | 久久久精品一区二区三区 | 亚洲伦理精品 | 在线草 | 97国产情侣爱久久免费观看 | 99热这里精品 | 国产粉嫩在线 | 精品国产欧美一区二区三区不卡 | 黄色三级在线看 | 天天射天天爱天天干 | 西西4444www大胆视频 | 国产福利av在线 | 十八岁免进欧美 | 日韩av图片 | 999超碰 | 99精品久久99久久久久 | 香蕉视频在线免费 | 碰超在线观看 | 深夜福利视频在线观看 | 开心激情婷婷 | 久久久久一区二区三区 | 日韩av福利在线 | 狠狠操狠狠干天天操 | 日韩成人邪恶影片 | 91精品国自产在线 | 99热在线免费观看 | 久久婷婷五月综合色丁香 | 日韩av中文 | 丁香久久综合 | 亚洲精品tv久久久久久久久久 | 午夜天使| 开心激情五月婷婷 | 亚洲欧洲av在线 | 久草在线99 | 在线免费观看一区二区三区 | 二区三区在线视频 | 最近2019年日本中文免费字幕 | 九九九热精品免费视频观看 | 久久情爱 | 国产毛片在线 | 国产精品2020 | 欧美一区二视频在线免费观看 | 麻豆果冻剧传媒在线播放 | 国产精品毛片久久久 | 玖玖玖影院 | 欧美老少交 | 黄色在线成人 | 在线中文字幕一区二区 | 欧美日韩一二三四区 | 亚洲国产欧美一区二区三区丁香婷 | 99在线免费观看视频 | 免费高清在线观看电视网站 | 亚洲综合射| 成人在线观看免费视频 | 日韩精品视频免费在线观看 | 香蕉网址 | 中文字幕视频网 | 久久久久久久久久久久电影 | 亚洲人在线| 久久久久久久国产精品影院 | 婷婷丁香导航 | 久久香蕉一区 | 黄色三级免费观看 | 亚洲最新毛片 | 久久国产精品一区二区三区 | 国产精品久久久久影院 | 国产三级香港三韩国三级 | 久久久影院一区二区三区 | 国产在线2020 | 欧美黑人巨大xxxxx | 在线成人小视频 | 亚洲成人在线免费 | 色黄久久久久久 | 日本精品久久 | www.久热 | 国产黄色片在线免费观看 | 超碰在线天天 | 99久久www | 日韩视| 一本一道久久a久久精品 | 夜夜嗨av色一区二区不卡 | 欧美激情精品久久久久久免费印度 | 欧美视频www | 九九视频免费在线观看 | 国内精品久久天天躁人人爽 | 免费 在线 中文 日本 | 亚洲精品中文字幕在线观看 | 人人揉人人揉人人揉人人揉97 | 97视频在线免费观看 | 操操操天天操 | 国产精品久久久久久久免费大片 | 在线观看久草 | 91福利国产在线观看 | 国产永久免费 | 麻豆视频在线观看 | 最新成人在线 | 中文字幕中文字幕中文字幕 | www.夜夜爱 | 久久久久久99精品 | 99 视频 高清 | 国产青春久久久国产毛片 | 精品超碰| 91av影视 | 国产成人精品一区二 | 特级毛片爽www免费版 | 天天骚夜夜操 | 中文字幕av全部资源www中文字幕在线观看 | 亚洲婷久久 | 丁香视频免费观看 | 久久亚洲电影 | 在线一区av | 天堂av色婷婷一区二区三区 | 国产精品一区二区视频 | 欧美性免费 | 免费观看性生交大片3 | 久久国产精品99久久久久久丝袜 | 精品五月天 | 久久久久亚洲国产精品 | 精品久久久久久综合日本 | 亚洲国产久 | 日韩免费av在线 | 一区二区视频在线免费观看 | 亚洲一区免费在线 | 亚色视频在线观看 | 视频成人免费 | 丁香六月网 | 亚洲男女精品 | 国产精品高清在线 | 中文字幕首页 | 黄污污网站 | 久久激情视频网 | 欧美少妇xxxxxx | 欧洲黄色片 | 精品毛片久久久久久 | 精品视频 | 成人免费xyz网站 | 国产精品一区免费观看 | 99国产精品久久久久久久久久 | 久久久久久毛片精品免费不卡 | 99国产视频在线 | 中文字幕黄网 | 欧美人人爱 | 在线国产福利 | 婷婷九月丁香 | 日本在线观看一区二区三区 | 国产无吗一区二区三区在线欢 | 天天操天 | 在线观看岛国 | 久久九九九九 | 91麻豆精品91久久久久同性 | 超碰精品在线 | 久久玖| 嫩草91影院 | 国产精品久久久久久久久软件 | 九热精品| 精品国产乱码久久久久久1区二区 | 日韩成人精品在线观看 | 成人免费视频网站在线观看 | 99re6热在线精品视频 | 青青网视频 | 激情文学综合丁香 | 激情av五月婷婷 | 亚洲精品视频播放 | 久久中文字幕在线视频 | 91精品国产乱码 | 2021国产精品视频 | 日韩欧美一区二区在线 | 中文字幕精品一区二区精品 | 成年人在线看片 | 91成人小视频 | 午夜影院先 | 波多野结依在线观看 | 亚洲精品久久在线 | 91香蕉亚洲精品 | 欧美成人在线免费观看 | 亚洲国产日韩欧美在线 | 在线播放一区二区三区 | 国产成人精品av | 四虎国产精品免费 | 色狠狠综合天天综合综合 | 日韩在线观看视频一区二区三区 | 国产精品久久综合 | 91手机电视 | 欧美精品一区二区免费 | 色a综合 | 在线视频黄| 黄色软件在线看 | 免费观看视频的网站 | 精品资源在线 | 六月丁香激情综合 | 91精选 | 天堂网av在线 | www.日韩免费 | 操操操日日 | 久久精品国产久精国产 | 国产一区二区三精品久久久无广告 | 亚洲在线视频免费 | 国产福利一区二区在线 | 日本精品视频在线播放 | 久久免费视频在线观看30 | 久久国产精品一区二区三区四区 | 8x成人免费视频 | 久久久久亚洲精品国产 | 精品国产乱码久久久久久1区2匹 | 最新色站 | 超碰在线人 | 久久精品网站视频 | 婷婷亚洲激情 | 高清不卡一区二区在线 | 国产精品video爽爽爽爽 | 91看片淫黄大片在线播放 | 亚洲黄色在线免费观看 | 在线天堂8√| 亚州精品在线视频 | 天天干天天射天天操 | 一级黄色免费 | 中文字幕一区二区在线观看 | 最近中文字幕久久 | 国产精品不卡一区 | 欧洲亚洲精品 | 97国产精品亚洲精品 | 国产尤物在线视频 | 91自拍视频在线观看 | 久久久免费在线观看 | 久久久性 | 国产一区二区在线免费观看 | 亚洲国产欧美在线人成大黄瓜 | 人人爽人人干 | 在线视频精品 | 国色天香av | 久久国产精品99久久久久久老狼 | 久久久精品国产一区二区三区 | 欧美一级淫片videoshd | 亚洲成人家庭影院 | 久久精品资源 | 人人爱人人舔 | 日韩美女高潮 | 91av播放| 国产欧美中文字幕 | 亚洲最新视频在线播放 | 五月婷网站 | 91精品视频免费观看 | 日日爱av | 久久免费福利 | 色婷婷综合在线 | 日韩不卡高清 | 国产一区二区三区午夜 | 国产精品99久久久久久人免费 | 超碰成人网 | 99久久久国产精品免费观看 | av三级av | 久草在线视频网站 | 欧美高清视频不卡网 | 国产精品美女久久久久久网站 | 国产福利一区二区在线 | 欧美色图一区 | 亚洲视屏 | 亚洲精品456在线播放 | 天天射天天射 | 国产高清第一页 | 日韩欧美精品免费 | 久久人人爽人人人人片 | 久久久久视 | www..com毛片| 一级淫片在线观看 | av片在线观看免费 | 国产精品久久久久9999吃药 | 欧洲亚洲女同hd | 激情开心色 | 亚洲国产成人精品在线 | 免费人人干 | 日韩视频免费在线观看 | 国产精品va | 欧美视频二区 | 国产分类视频 | 国产精品麻豆三级一区视频 | 91色一区二区三区 | 亚洲视频免费视频 | 在线观看黄网站 | 五月天激情综合 | 狠狠色噜噜狠狠狠狠 | 午夜av在线播放 | 在线免费视频a | 国产馆在线播放 | 99视频免费观看 | 福利视频一区二区 | 婷婷丁香激情综合 | 九九视频网 | 国产视频日韩 | 欧美一级片在线播放 | 99久在线精品99re8热视频 | 干天天| 97在线精品国自产拍中文 | 成人黄色电影在线播放 | www.com久久久| 91视频在线免费观看 | 亚洲国产精品成人综合 | 91精品伦理 | 午夜久久视频 | 色网站在线免费观看 | 国产精品色婷婷视频 | 视频二区在线 | 久久99精品国产99久久6尤 | 婷婷综合久久 | 69视频国产 | 国产亚洲视频在线免费观看 | 不卡视频一区二区三区 | 亚洲色图22p | 91成人精品一区在线播放 | 六月丁香在线观看 | 色天天综合久久久久综合片 | 日本黄色黄网站 | 国产精品福利在线观看 | 国产在线专区 | 亚洲精品短视频 | 91禁在线看 | 国产成人精品在线观看 | 五月婷婷激情六月 | 五月婷婷av | 综合网伊人 | 最近日本中文字幕 | 99re中文字幕 | 亚洲永久精品一区 | 日免费视频 | 天天操夜夜曰 | 综合久久久久久久久 | 911精品视频 | 国产乱对白刺激视频不卡 | 亚洲国产精品500在线观看 | 久久久久久久av麻豆果冻 | 91九色蝌蚪视频 | 欧美韩国日本在线观看 | 日韩在线观看一区二区 | 免费在线播放av电影 | 久久综合桃花 | 一区二区精品国产 | 日韩高清一区二区 | 久久久综合精品 | 最新色站| 久久色中文字幕 | 午夜手机看片 | 99久精品视频 | 国产成人精品亚洲日本在线观看 | 99久久精品日本一区二区免费 | 精品一区二区日韩 | 在线观看的a站 | 黄a网站 | 婷婷在线综合 | 伊人春色电影网 | 成人资源在线播放 | 成年人视频在线免费观看 | 成人毛片久久 | 日韩影片在线观看 | 麻豆传媒视频在线播放 | 日本激情视频中文字幕 | 国产精品18久久久久久久网站 | 国内三级在线观看 | 精品久久1| www激情com | 日韩视频中文字幕 | 久久久久久久99 | 国产视频在线看 | 国产黄a三级三级 | 欧美特一级片 | 激情综合婷婷 | 一区二区伦理电影 | 欧美日韩一区二区三区在线免费观看 | 在线免费视频一区 | 亚洲国产中文字幕在线视频综合 | av播放在线| 九九视频免费观看视频精品 | 麻花传媒mv免费观看 | 92国产精品久久久久首页 | 国产精品女教师 | 欧美日韩视频网站 | 一区二区中文字幕在线 | 欧美精品在线观看免费 | 99九九视频 | 亚洲 欧美 国产 va在线影院 | 在线小视频 | 成人免费在线播放 | 在线网站黄 | 国产白浆视频 | 免费在线观看午夜视频 | 日韩av一区二区在线 | 中中文字幕av| 草免费视频 | 美女禁18| 亚洲精品一区二区网址 | 97国产小视频 | 国内久久久久久 | 激情开心 | 久久九九免费视频 | 亚洲欧美视频 | 18国产精品白浆在线观看免费 | 日韩亚洲国产精品 | 国产手机视频在线观看 | 一区二区高清在线 | 久久综合精品国产一区二区三区 | 一区二区久久 | 97免费视频在线 | 久久爽久久爽久久av东京爽 | 五月宗合网 | 一二三精品视频 | 国产精品欧美久久久久无广告 | 日韩久久精品 | 99视频这里只有 | 久久婷婷精品 | 91精品办公室少妇高潮对白 | 中文字幕在线成人 | 人操人 | 中文字幕无吗 | 亚洲精品乱码白浆高清久久久久久 | 在线91网 | 伊人天天综合 | 国产手机在线播放 | 国产二区免费视频 | 2019av在线视频 | 九九九在线观看视频 | 超级碰碰碰免费视频 | 国产成人久久av | 在线观看岛国 | 天天干天天做 | 国产黄色免费看 | 综合网天天 | 在线免费视频 你懂得 | 超碰在线观看av.com | 国产亚洲精品免费 | 成人在线观看资源 | www.综合网.com| 日韩在线观看第一页 | 最近的中文字幕大全免费版 | 欧美久久久久 | 欧美二区三区91 | 91漂亮少妇露脸在线播放 | 99视频免费在线观看 | www天天干 | 国产一区二区中文字幕 | 日韩激情视频在线 | 99热在线精品观看 | 国产精品久久久久久69 | 久色婷婷| 黄色av一区二区三区 | 成人h动漫精品一区二 | 天天综合天天综合 | 91精品国产综合久久久久久久 | 国产精品久久久久久五月尺 | 久久久2o19精品 | 欧美日韩在线免费观看 | 亚洲人人网 | 午夜精品久久久久久久久久久 | 久久久久久福利 | 亚洲aⅴ一区二区三区 | 久久精品国产精品亚洲精品 | 精品欧美一区二区在线观看 | 国产剧情av在线播放 | 97自拍超碰 | 久久a免费视频 | 免费看三级 | 婷婷伊人网 | 97成人精品区在线播放 | 97av色 | 亚洲精品66| 国产在线综合视频 | 天天综合区 | 日韩激情视频在线 | 国产一级大片在线观看 | 五月婷婷深开心 | 国产一级精品在线观看 | 99久久99视频 | 人人澡人人添人人爽一区二区 | 69av网| 国产在线看 | 亚州日韩中文字幕 | 日本久热 | 在线电影 你懂得 | 亚洲jizzjizz日本少妇 | 五月婷婷,六月丁香 | 国产麻豆精品免费视频 | 久久社区视频 | av免费高清观看 | 天天操偷偷干 | 9999国产精品 | 日日夜夜人人精品 | 999国内精品永久免费视频 | 亚洲精品成人网 | 免费精品在线视频 | 18网站在线观看 | 日韩免费在线视频 | 99久久99热这里只有精品 | 精品欧美一区二区在线观看 | 免费在线播放av电影 | 成人网444ppp| 成+人+色综合 | 91av中文| 中文字幕一二三区 | 国产精品国产三级国产专区53 | 国产精品免费麻豆入口 | 超碰人人舔| 中文字幕中文字幕在线中文字幕三区 | 久久国产精品视频免费看 | 国产亚洲精品日韩在线tv黄 | 免费激情在线电影 | 97色噜噜| 91在线亚洲 | 婷婷成人在线 | 91精品国产欧美一区二区成人 | 日韩精品中字 | 国产精品久久久久一区 | 亚洲精品视频在线观看免费视频 | 在线视频区 | 亚洲国产精品99久久久久久久久 | 国产精品一区二区三区在线播放 | 欧美日韩国产欧美 | 成人黄色小说在线观看 | 91精品久久久久久久99蜜桃 | 亚洲美女在线一区 | 日批视频 | 国产精品国内免费一区二区三区 | 久久人人精品 | 国产成人精品一区二区三区福利 | 五月天激情视频 | 国产精品精品久久久久久 | 亚洲精品中文字幕在线观看 | 成人免费在线播放 | 日本公妇在线观看 | 东方av在| 国产.精品.日韩.另类.中文.在线.播放 | 手机av资源 | 91成人在线看 | 中文字幕亚洲精品在线观看 | 特级大胆西西4444www | 激情网站五月天 | 亚洲 欧美 91| 国产精品美女999 | 国产亚洲精品bv在线观看 | 国产特级毛片aaaaaaa高清 | 欧美另类v| 国产精品电影一区二区 | a视频免费看 | 日韩三级免费 | 色久天 | 国产精品日韩在线播放 | 美女黄频免费 | 韩国精品在线观看 | 国产精品久久久久一区二区国产 | 99色在线观看视频 | 日日夜夜精品视频天天综合网 | 中文字幕在线看视频国产中文版 | 久久精品久久久久电影 | 日本中文字幕在线播放 | 四虎国产精品成人免费影视 | 国产日韩精品一区二区在线观看播放 | 美女一级毛片视频 | www日韩精品 | 久久精品视频网址 | 久久精品区| 欧美日韩不卡在线观看 | 亚洲精品777 | 99久久日韩精品免费热麻豆美女 | 亚洲片在线 | 成人午夜电影在线播放 | 中文字幕色在线视频 | 免费一级特黄录像 | 国产美腿白丝袜足在线av | 中文字幕你懂的 | 国产黄色片免费看 | 最新日本中文字幕 | 国产一区在线免费观看 | 亚洲干视频在线观看 | 亚洲高清在线视频 | 国产呻吟在线 | 国产精品福利av | 中文字幕精品久久 | 中文字幕一区二区三区久久蜜桃 | 久草热久草视频 | 久草在线资源网 | 精品免费一区二区三区 | 久久久99国产精品免费 | 一区二区精品在线观看 | 亚洲麻豆精品 | 2021国产精品视频 | 精品国产精品久久 | 亚洲资源在线 | 91新人在线观看 | 国产一区在线播放 | 高清国产一区 | 亚洲第一中文网 | 西西www4444大胆视频 | wwwwww国产| 99热 精品在线 | 亚洲综合在线视频 | 欧美日韩国产伦理 | 一区二区三区av在线 | 国产成人一区在线 | 欧美日韩大片在线观看 | 五月婷社区 | 狠狠色丁香婷婷综合 | 欧美大片在线观看一区 | 亚洲视频在线播放 | 久久久久国产一区二区三区四区 | 亚洲激情在线视频 | 国产色视频一区二区三区qq号 | 日本在线观看中文字幕 | av中文字幕不卡 | 天天操天天摸天天干 | 成人99免费视频 | 久久不卡日韩美女 | caobi视频 | 天天干天天操天天爱 | 成人黄色一级视频 | 91日韩在线 | 免费av试看 | 美女黄频| 手机看片国产日韩 | 午夜精品99久久免费 | www.福利| 五月婷婷播播 | 久久99精品久久久久久三级 | 久久精品一区二区三区四区 | 91经典在线| 日韩欧美国产激情在线播放 | 丁香婷婷久久久综合精品国产 | 国偷自产视频一区二区久 | 亚洲精品综合欧美二区变态 | 国产精品精品 | 久久久久国产精品视频 | 中文一区二区三区在线观看 | 欧美午夜性生活 | 久久免费精彩视频 | 国产在线999| 亚洲精品国产精品国自 | 亚洲午夜精品电影 | 久久草 | 亚洲国产三级在线 | 国产小视频你懂的在线 | 亚洲精品在线免费 | 成人毛片一区 | 国产小视频在线播放 | 色综合久久五月 | 欧美日韩在线电影 | 午夜精品久久久 | 在线观看91视频 | 亚洲第一av在线播放 | 亚洲精品 在线视频 | 国产一区在线免费观看视频 | 中文字幕日韩免费视频 | 精品国产伦一区二区三区免费 | 超薄丝袜一二三区 | 国产乱码精品一区二区蜜臀 | 色999视频 | 国产三级午夜理伦三级 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | av网站手机在线观看 | 色偷偷网站视频 | 久久国产影院 | 成年人黄色在线观看 | 热久久最新地址 | 久久国产a| 中文字幕在线观看你懂的 | 亚洲国产高清在线观看视频 | 色视频在线观看 | 97超碰在线人人 | 伊人超碰在线 | 成年人在线免费看视频 | av理论电影 | 欧美一区二区三区在线看 | 中文字幕日韩伦理 | 欧美资源在线观看 | 在线黄av| 国产精品 日韩 欧美 | x99av成人免费 | 日韩免费高清在线 | 久久久精品国产一区二区电影四季 | www.69xx | 玖玖玖在线 | 亚洲精品免费在线观看视频 | 天天综合网天天 | 婷婷在线视频观看 |