精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Facebook:如何在Golang中搭建GraphQL?

開發(fā) 前端
本文將重點(diǎn)介紹GraphQL的主要功能,以及就API而言它存在的優(yōu)缺點(diǎn)。文末將展示一個使用Golang的簡單程序(已搭建GraphQL)。

本文轉(zhuǎn)載自公眾號“讀芯術(shù)”(ID:AI_Discovery)。

多年來,人們一直在使用REST API來滿足開發(fā)需求,但得完成大量不必要的調(diào)用后,開發(fā)者才能靈活使用。例如,如果Web和移動設(shè)備所需的數(shù)據(jù)不同,我們還須針對Web和移動設(shè)備創(chuàng)建兩個不同的端點(diǎn)。

因此,F(xiàn)acebook創(chuàng)建了一種查詢語言——GraphQL,該語言可以準(zhǔn)確地給出開發(fā)者查詢的內(nèi)容,干凈利落,也讓 API 更容易地隨著時間推移而演進(jìn),還能用于構(gòu)建強(qiáng)大的開發(fā)者工具。

本文將重點(diǎn)介紹GraphQL的主要功能,以及就API而言它存在的優(yōu)缺點(diǎn)。文末將展示一個使用Golang的簡單程序(已搭建GraphQL)。

什么是GraphQL?

GraphQL是用于API的查詢語言,它是服務(wù)器端運(yùn)行時,通過為數(shù)據(jù)定義的類型系統(tǒng)執(zhí)行查詢。

GraphQL是一種查詢語言,適用許多領(lǐng)域,但通常用來在客戶端和服務(wù)器應(yīng)用程序之間搭橋。無所謂使用的是哪個網(wǎng)絡(luò)層,所以可以在客戶端和服務(wù)器應(yīng)用程序之間讀取和寫入數(shù)據(jù)。(RobinWieruch《GraphQL指南》)

雖然GraphQL是查詢語言,但它與數(shù)據(jù)庫沒有直接關(guān)系,也就是GraphQL不限于任意SQL或是NoSQL的數(shù)據(jù)庫。GraphQL位于客戶端和服務(wù)器端,通過API連接/訪問。開發(fā)這種查詢語言的目的之一是通過提供所需的數(shù)據(jù)來促進(jìn)后端、前端或移動應(yīng)用程序之間的數(shù)據(jù)通信。

Facebook:如何在Golang中搭建GraphQL?

GraphQL的操作

1. 查詢(Query)

查詢用于讀取或獲取值。無論哪種情況,操作都是一個簡單的字符串,GraphQL服務(wù)器可以解析該字符串并以特定格式的數(shù)據(jù)進(jìn)行響應(yīng)。

你可以使用查詢操作從API請求數(shù)據(jù)。查詢描述需要從GraphQL服務(wù)器獲取的數(shù)據(jù),發(fā)送查詢其實(shí)是按字段要求提取數(shù)據(jù)。(Eve Porcello、Alex Banks著《學(xué)習(xí)GraphQL》)

Facebook:如何在Golang中搭建GraphQL?

2. 模式(Schema)

GraphQL使用Schema描述數(shù)據(jù)圖的形狀。這樣的Schema定義類型的層次結(jié)構(gòu),依托的是從后端數(shù)據(jù)存儲區(qū)填充的字段,也準(zhǔn)確表示客戶端可以對數(shù)據(jù)圖執(zhí)行哪些查詢和突變。

3. 分解器(Resolver)

分解器是負(fù)責(zé)為Schema單一字段填充數(shù)據(jù)的功能。它可以用你定義的任何方式填充該數(shù)據(jù),例如從后端數(shù)據(jù)庫或第三方API提取數(shù)據(jù)。

4. 突變(Mutation)

修改數(shù)據(jù)存儲中的數(shù)據(jù)并返回一個值,它可用于插入、更新或刪除數(shù)據(jù)。

突變與查詢原理相同:它具有字段和對象、參數(shù)和變量、片段和操作名稱,以及返回結(jié)果的指令和嵌套對象。(Robin Wieruch著《GraphQL之路》)

Facebook:如何在Golang中搭建GraphQL?

5. 訂閱(Subscription)

將數(shù)據(jù)從服務(wù)器推送到客戶端的方法是選擇偵聽來自服務(wù)器的實(shí)時消息。

GraphQL的訂閱來自Facebook的真實(shí)用例。開發(fā)團(tuán)隊(duì)希望找到一種方法,不刷新頁面就能實(shí)時顯示發(fā)文獲得的有效點(diǎn)贊(Live Likes)。(Eve Porcello、Alex Banks著《學(xué)習(xí)GraphQL》)

Facebook:如何在Golang中搭建GraphQL?

GraphQL的優(yōu)勢與劣勢

Facebook:如何在Golang中搭建GraphQL?

1. 優(yōu)勢

(1) 開發(fā)迅速

來看一個案例:如何得到圖書借閱者的數(shù)據(jù)。在視圖中,首先我要顯示書籍列表,書籍列表菜單顯示中出現(xiàn)一個借閱者的列表。在REST API中,需要創(chuàng)建新的端點(diǎn)以返回圖書清單,再創(chuàng)建一個新的端點(diǎn)以返回每本書的借閱人。

Facebook:如何在Golang中搭建GraphQL?

與REST API不同,GraphQL中僅使用一個端點(diǎn)就可以返回書籍列表和借閱者列表了。

Facebook:如何在Golang中搭建GraphQL?

使用以下示例GraphQL查詢:

Facebook:如何在Golang中搭建GraphQL?

(2) 靈活性

來看一個案例:如何獲取書籍詳細(xì)信息。在網(wǎng)絡(luò)視圖上,我想展示書籍詳細(xì)信息,例如名稱、價格和介紹。在REST API中需要創(chuàng)建一個新的端點(diǎn)以返回名稱、價格、介紹等的書籍詳細(xì)信息。

Facebook:如何在Golang中搭建GraphQL?

如果在移動端查看時,只想展示圖書詳細(xì)信息中的名稱和價格怎么辦?如果使用與Web視圖相同的端點(diǎn),則會浪費(fèi)介紹的數(shù)據(jù)。所以需要更改該端點(diǎn)內(nèi)部的現(xiàn)有邏輯,或創(chuàng)建一個新的端點(diǎn)。

Facebook:如何在Golang中搭建GraphQL?

與REST API不同,GraphQL中僅使用一個端點(diǎn)即可按照Web或移動設(shè)備的需求返回書籍詳細(xì)信息。在GraphQL中,只需更改查詢。

(3) 維護(hù)簡單,易于使用

  • Rest API:如果客戶端需要其他數(shù)據(jù),通常需要添加一個新端點(diǎn)或更改一個現(xiàn)有端點(diǎn)。
  • GraphQL:客戶只需要更改查詢。

2. 缺點(diǎn)

  • 處理文件上傳:GraphQL規(guī)范中沒有關(guān)于文件上傳的內(nèi)容,并且突變不接受參數(shù)中的文件。
  • 簡單的API:如果你的API非常簡單,那GraphQL只會使其復(fù)雜,所以使用REST API可能會更好。

代碼實(shí)現(xiàn)

實(shí)現(xiàn)過程使用了Golang編程語言,這里是項(xiàng)目架構(gòu):

Facebook:如何在Golang中搭建GraphQL?

在依賴版本和依賴管理功能上使用的是go模塊。用graphql-go來支持查詢、突變和訂閱;用graphql-go-handler來支持處理器。此時,我將創(chuàng)建一個簡單的程序,這里使用GraphQL為詳細(xì)書目創(chuàng)建CRUD。步驟如下:

先新建一個環(huán)境文件夾,然后新建一個名為connection.yml的文件:

  1. app: 
  2. name: "GraphQL Test" 
  3. debug: true 
  4. port: "8080" 
  5. host: "localhost" 
  6. service: "http" 
  7. context: 
  8. timeout: 2 
  9. databases: 
  10. mongodb: 
  11. name: "local_db" 
  12. connection: "mongodb://root:root@localhost:27017" 

然后創(chuàng)建一個架構(gòu)文件夾,創(chuàng)建名為databaseConfiguration.go、environmentConfiguration.go和model.go的文件。這個文件夾用來配置數(shù)據(jù)庫并從connection.yml讀取數(shù)據(jù)。

(1) databaseConfiguration.go

  1. package infrastructureimport( 
  2.    "context" 
  3.   "go.mongodb.org/mongo-driver/mongo" 
  4.   "go.mongodb.org/mongo-driver/mongo/options" 
  5.    "log" 
  6. )var Mongodb *mongo.Databasefunc(e *Environment) InitMongoDB()(db *mongo.Database, err error) { 
  7. clientOptions :=options.Client().ApplyURI(e.Databases["mongodb"].Connection) 
  8.    client, err :mongo.Connect(context.TODO(),clientOptions) 
  9.    err = client.Ping(context.TODO(), nil) 
  10. if err != nil { 
  11. return db, err 
  12.    } 
  13. Mongodb = client.Database(e.Databases["mongodb"].Name) 
  14. log.Println("Mongodb Ready!!!") 
  15. return db, err 

(2) environmentConfiguration.go

  1. package infrastructureimport( 
  2.    "io/ioutil" 
  3.    "log" 
  4.    "os" 
  5.    "path" 
  6.   "runtime""gopkg.in/yaml.v2" 
  7. )func(env *Environment) SetEnvironment() { 
  8.    _, filename, _, _ :runtime.Caller(1) 
  9. env.path = path.Join(path.Dir(filename),"environment/Connection.yml") 
  10.    _, err :os.Stat(env.path) 
  11. if err != nil { 
  12.       panic(err) 
  13. return 
  14. }func(env *Environment) LoadConfig() { 
  15.    content, err :=ioutil.ReadFile(env.path) 
  16. if err != nil { 
  17. log.Println(err) 
  18.       panic(err) 
  19.    } 
  20.    err =yaml.Unmarshal([]byte(string(content)), env) 
  21. if err != nil { 
  22. log.Println(err) 
  23.       panic(err) 
  24.    } 
  25. if env.App.Debug == false { 
  26. log.SetOutput(ioutil.Discard) 
  27.    } 
  28. log.Println("Config load successfully!") 
  29. return 

(3) model.go

  1. package infrastructuretypeapp struct{ 
  2. Appname     string `yaml:"name"` 
  3.    Debug       bool  `yaml:"debug"` 
  4.    Port        string `yaml:"port"` 
  5.    Service     string `yaml:"service"` 
  6.    Host        string `yaml:"host"` 
  7. }type database struct { 
  8.    Name       string `yaml:"name"` 
  9.    Connection string`yaml:"connection"` 
  10. }type Environment struct { 
  11.    App       app                 `yaml:"app"` 
  12.    Databases map[string]database`yaml:"databases"` 
  13.    path      string 

第三,創(chuàng)建一個書目文件夾,創(chuàng)建如下文件:

Facebook:如何在Golang中搭建GraphQL?

model.go:

  1. package 
  2. package booktypeBook struct { 
  3.    Name        string 
  4.    Price       string 
  5.    Description string 
  6. } booktypeBook struct {   Name        string   Price       string   Description string} 

resolver.go:

  1. package bookimport( 
  2.   "context""github.com/graphql-go/graphql" 
  3. )var productType = graphql.NewObject( 
  4. graphql.ObjectConfig{ 
  5.       Name: "Book", 
  6.       Fields: graphql.Fields{ 
  7.          "name": &graphql.Field{ 
  8.             Type: graphql.String, 
  9.          }, 
  10.          "price":&graphql.Field{ 
  11.             Type: graphql.String, 
  12.          }, 
  13.          "description":&graphql.Field{ 
  14.             Type: graphql.String, 
  15.          }, 
  16.       }, 
  17.    }, 
  18. )var queryType = graphql.NewObject( 
  19. graphql.ObjectConfig{ 
  20.       Name: "Query", 
  21.       Fields: graphql.Fields{ 
  22.          "book":&graphql.Field{ 
  23.             Type:        productType, 
  24.             Description: "Get bookby name", 
  25. Args: graphql.FieldConfigArgument{ 
  26.                "name":&graphql.ArgumentConfig{ 
  27.                   Type: graphql.String, 
  28.                }, 
  29.             }, 
  30.             Resolve: func(pgraphql.ResolveParams) (interface{}, error) { 
  31. var result interface{} 
  32.                name, ok :=p.Args["name"].(string) 
  33. if ok { 
  34.                   // Find product 
  35.                   result =GetBookByName(context.Background(), name) 
  36.                } 
  37. return result, nil 
  38.             }, 
  39.          }, 
  40.          "list":&graphql.Field{ 
  41.             Type:        graphql.NewList(productType), 
  42.             Description: "Get booklist", 
  43. Args: graphql.FieldConfigArgument{ 
  44.                "limit":&graphql.ArgumentConfig{ 
  45.                   Type: graphql.Int, 
  46.                }, 
  47.             }, 
  48.             Resolve: func(paramsgraphql.ResolveParams) (interface{}, error) { 
  49. var result interface{} 
  50.                limit, _ :=params.Args["limit"].(int) 
  51.                result =GetBookList(context.Background(), limit) 
  52. return result, nil 
  53.             }, 
  54.          }, 
  55.       }, 
  56.    })var mutationType =graphql.NewObject(graphql.ObjectConfig{ 
  57.    Name: "Mutation", 
  58.    Fields: graphql.Fields{ 
  59.       "create":&graphql.Field{ 
  60.          Type:        productType, 
  61.          Description: "Create newbook", 
  62. Args: graphql.FieldConfigArgument{ 
  63.             "name":&graphql.ArgumentConfig{ 
  64.                Type:graphql.NewNonNull(graphql.String), 
  65.             }, 
  66.             "price":&graphql.ArgumentConfig{ 
  67.                Type:graphql.NewNonNull(graphql.String), 
  68.             }, 
  69.             "description":&graphql.ArgumentConfig{ 
  70.                Type:graphql.NewNonNull(graphql.String), 
  71.             }, 
  72.          }, 
  73.          Resolve: func(paramsgraphql.ResolveParams) (interface{}, error) { 
  74.             book :Book
  75.                Name:        params.Args["name"].(string), 
  76.                Price:       params.Args["price"].(string), 
  77.                Description:params.Args["description"].(string), 
  78.             } 
  79. if err :InsertBook(context.Background(), book); err != nil { 
  80. return nil, err 
  81.             }return book, nil 
  82.          }, 
  83.       },"update":&graphql.Field{ 
  84.          Type:        productType, 
  85.          Description: "Update bookby name", 
  86. Args: graphql.FieldConfigArgument{ 
  87.             "name":&graphql.ArgumentConfig{ 
  88.                Type:graphql.NewNonNull(graphql.String), 
  89.             }, 
  90.             "price":&graphql.ArgumentConfig{ 
  91.                Type: graphql.String, 
  92.             }, 
  93.             "description":&graphql.ArgumentConfig{ 
  94.                Type: graphql.String, 
  95.             }, 
  96.          }, 
  97.          Resolve: func(paramsgraphql.ResolveParams) (interface{}, error) { 
  98.             book :Book{} 
  99. if name, nameOk :params.Args["name"].(string); nameOk { 
  100. book.Name = name 
  101.             } 
  102. if price, priceOk :params.Args["price"].(string); priceOk { 
  103. book.Price = price 
  104.             } 
  105. if description, descriptionOk :=params.Args["description"].(string); descriptionOk { 
  106. book.Description = description 
  107.             }if err :=UpdateBook(context.Background(), book); err != nil { 
  108. return nil, err 
  109.             } 
  110. return book, nil 
  111.          }, 
  112.       },"delete": &graphql.Field{ 
  113.          Type:        productType, 
  114.          Description: "Delete bookby name", 
  115. Args: graphql.FieldConfigArgument{ 
  116.             "name":&graphql.ArgumentConfig{ 
  117.                Type:graphql.NewNonNull(graphql.String), 
  118.             }, 
  119.          }, 
  120.          Resolve: func(paramsgraphql.ResolveParams) (interface{}, error) { 
  121.             name, _ :=params.Args["name"].(string) 
  122. if err :DeleteBook(context.Background(), name); err != nil { 
  123. return nil, err 
  124.             } 
  125. return name, nil 
  126.          }, 
  127.       }, 
  128.    }, 
  129. })// schema 
  130. var Schema, _ = graphql.NewSchema( 
  131. graphql.SchemaConfig{ 
  132.       Query:    queryType, 
  133.       Mutation: mutationType, 
  134.    }, 

repository.go:

  1. package bookimport( 
  2.    "context" 
  3.    "log""graphql/infrastructure""go.mongodb.org/mongo-driver/bson" 
  4.   "go.mongodb.org/mongo-driver/mongo/options" 
  5. )funcGetBookByName(ctxcontext.Context, name string) (result interface{}){ 
  6. var book Book 
  7.    data :=infrastructure.Mongodb.Collection("booklist").FindOne(ctx,bson.M{"name": name}) 
  8. data.Decode(&book) 
  9. return book 
  10. }funcGetBookList(ctxcontext.Context, limit int) (result interface{}){ 
  11. var book Book 
  12. var books []Bookoption :options.Find().SetLimit(int64(limit))cur, err:infrastructure.Mongodb.Collection("booklist").Find(ctx, bson.M{},option) 
  13. defer cur.Close(ctx) 
  14. if err != nil { 
  15. log.Println(err) 
  16. return nil 
  17.    } 
  18. for cur.Next(ctx) { 
  19. cur.Decode(&book) 
  20.       books = append(books, book) 
  21.    } 
  22. return books 
  23. }funcInsertBook(ctxcontext.Context, book Book) error { 
  24.    _, err :=infrastructure.Mongodb.Collection("booklist").InsertOne(ctx, book) 
  25. return err 
  26. }funcUpdateBook(ctxcontext.Context, book Book) error { 
  27.    filter :bson.M{"name":book.Name} 
  28.    update :bson.M{"$set":book} 
  29. upsertBool :true 
  30. updateOption :options.UpdateOptions{ 
  31. Upsert: &upsertBool, 
  32.    } 
  33.    _, err :=infrastructure.Mongodb.Collection("booklist").UpdateOne(ctx, filter,update, &updateOption) 
  34. return err 
  35. }funcDeleteBook(ctxcontext.Context, name string) error { 
  36.    _, err :=infrastructure.Mongodb.Collection("booklist").DeleteOne(ctx,bson.M{"name": name}) 
  37. return err 

response.go:

  1. package bookimport( 
  2.    "encoding/json" 
  3.    "net/http" 
  4.    "time" 
  5. )type SetResponsestruct { 
  6.    Status     string     `json:"status"` 
  7.    Data       interface{} `json:"data,omitempty"` 
  8. AccessTime string     `json:"accessTime"` 
  9. }funcHttpResponseSuccess(w http.ResponseWriter, r *http.Request, data interface{}){ 
  10. setResponse :SetResponse
  11.       Status:     http.StatusText(200), 
  12. AccessTime: time.Now().Format("02-01-2006 15:04:05"), 
  13.       Data:       data} 
  14.    response, _ :=json.Marshal(setResponse) 
  15. w.Header().Set("Content-Type", "Application/json") 
  16. w.WriteHeader(200) 
  17. w.Write(response) 
  18. }funcHttpResponseError(w http.ResponseWriter, r *http.Request, data interface{},code int) { 
  19. setResponse :SetResponse
  20.       Status:     http.StatusText(code), 
  21. AccessTime: time.Now().Format("02-01-2006 15:04:05"), 
  22.       Data:       data} 
  23.    response, _ :=json.Marshal(setResponse) 
  24. w.Header().Set("Content-Type", "Application/json") 
  25. w.WriteHeader(code) 
  26. w.Write(response) 

routes.go:

  1. package bookimport( 
  2.    "github.com/go-chi/chi" 
  3.   "github.com/go-chi/chi/middleware" 
  4.   "github.com/graphql-go/handler" 
  5. )funcRegisterRoutes(r *chi.Mux) *chi.Mux { 
  6.    /* GraphQL */ 
  7. graphQL :handler.New(&handler.Config{ 
  8.       Schema:   &Schema, 
  9.       Pretty:   true, 
  10. GraphiQL: true, 
  11.    }) 
  12. r.Use(middleware.Logger) 
  13. r.Handle("/query", graphQL) 
  14. return r 

最后,創(chuàng)建名為 main.go的文件。

main.go:

  1. package mainimport( 
  2.    "github.com/go-chi/chi" 
  3.    "graphql/book" 
  4.    "graphql/infrastructure" 
  5.    "log" 
  6.    "net/http" 
  7.    "net/url" 
  8. )funcmain() { 
  9.    routes :chi.NewRouter() 
  10.    r :book.RegisterRoutes(routes) 
  11. log.Println("Server ready at 8080") 
  12. log.Fatal(http.ListenAndServe(":8080", r)) 
  13. }funcinit() { 
  14. val :url.Values{} 
  15. val.Add("parseTime", "1") 
  16. val.Add("loc", "Asia/Jakarta") 
  17.    env :infrastructure.Environment{} 
  18. env.SetEnvironment() 
  19. env.LoadConfig() 
  20. env.InitMongoDB() 

運(yùn)行程序的結(jié)果如下:

 

Facebook:如何在Golang中搭建GraphQL?

 

 

創(chuàng)建書目詳情示例

 

GraphQL有很多優(yōu)點(diǎn),但事實(shí)證明,與REST API相比,GraphQL處理文件上傳和簡單API的性能表現(xiàn)有所不足。因此,我們必須首先了解要構(gòu)建的系統(tǒng),是否適合將GraphQL用作應(yīng)用程序的設(shè)計架構(gòu)。

 

責(zé)任編輯:趙寧寧 來源: 今日頭條
相關(guān)推薦

2022-01-21 10:58:39

JavaScriptGolangPython

2024-11-12 08:00:00

LSM樹GolangMemTable

2021-05-07 09:06:55

GraphQLAPI 以太坊

2022-10-08 11:39:56

斷路器Golang項(xiàng)目

2015-05-25 09:13:31

NTP網(wǎng)絡(luò)時間協(xié)議NTP服務(wù)器

2022-03-28 08:00:00

數(shù)據(jù)庫GraphQL公共云

2022-01-05 18:19:30

容器鏡像Golang

2018-11-08 09:00:31

樹莓派WordPressLinux

2020-01-18 14:55:03

架構(gòu)運(yùn)維技術(shù)

2015-11-09 11:23:09

FacebookFOOMs

2023-11-09 09:13:48

GraphQLAPI 架構(gòu)

2016-07-26 13:58:52

Ubuntulinux網(wǎng)橋

2022-03-30 18:18:33

GolangTiDB數(shù)據(jù)庫

2018-07-03 09:48:30

Facebook 開發(fā)Python

2015-06-03 15:12:07

云端TFS微軟代碼管理環(huán)境

2019-05-09 09:00:00

WindowsKafka

2020-06-24 07:00:00

GraphQL API監(jiān)控

2014-04-15 15:14:49

UbuntuGhost博客平臺

2025-08-05 08:09:51

StarRocks本地搭建集群

2020-07-28 10:05:51

互聯(lián)網(wǎng)FacebookTikTok
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

欧美丰满高潮xxxx喷水动漫| 国产日本一区二区| 久久久久久久久国产| 免费黄色三级网站| 国精产品一区一区三区四川| 国产三级电影在线观看| av日韩在线播放| 一本色道综合亚洲| 日韩影片在线播放| 亚洲成人久久精品| 玖玖在线精品| 欧美日韩第一页| 日本污视频网站| 加勒比视频一区| 欧美日韩精品欧美日韩精品| 欧美啪啪免费视频| 嫩草在线视频| 久久久亚洲综合| av激情久久| 中文字幕乱码在线观看| 91久久久久| 久久亚洲精品视频| 欧美性猛交xxxx乱| 澳门久久精品| 欧美精品九九99久久| 无码人妻丰满熟妇区96| a毛片在线播放| 国产精品乱码妇女bbbb| 老牛影视免费一区二区| 精品国自产拍在线观看| 美女视频免费一区| 日韩女在线观看| 1级黄色大片儿| 欧美成人首页| 日日骚久久av| 丰满少妇一区二区| 精品亚洲精品| 精品久久国产字幕高潮| 天堂在线中文在线| 亚洲综合av一区二区三区| 精品久久久在线观看| www国产免费| 黄色免费在线看| 欧美国产丝袜视频| 日韩少妇中文字幕| 欧洲免费在线视频| 久久午夜老司机| 精品免费国产| 天堂中文字幕在线| 91亚洲国产成人精品一区二三| 3d蒂法精品啪啪一区二区免费| ,一级淫片a看免费| 激情深爱一区二区| 91九色国产视频| 国产麻豆精品一区| 国产麻豆日韩欧美久久| 亚洲综合成人婷婷小说| 国产夫妻性生活视频| 国产经典欧美精品| 99在线热播| 欧美熟妇乱码在线一区| 成人av电影在线| 精品无人乱码一区二区三区的优势| 亚洲精品一区二区三区四区| jvid福利写真一区二区三区| 鲁鲁狠狠狠7777一区二区| 欧美91精品久久久久国产性生爱| www国产精品av| 日韩美女一区| 老司机在线视频二区| 亚洲另类春色国产| 成年人网站国产| 性欧美18xxxhd| 91国模大尺度私拍在线视频| 亚洲欧美久久久久| 国产一区二区三区免费在线 | 深爱激情综合网| 一本大道久久加勒比香蕉| 欧美乱大交做爰xxxⅹ小说| 图片区亚洲欧美小说区| 欧美人交a欧美精品| 成人免费视频毛片| 蜜芽一区二区三区| yy111111少妇影院日韩夜片| 黄色av网址在线| 国产日本欧洲亚洲| gogogo免费高清日本写真| 国产在线xxx| 日韩欧美在线视频观看| 午夜两性免费视频| 一区二区在线视频观看| 亚洲精品永久免费| 老熟妻内射精品一区| 亚洲经典视频在线观看| 国产日韩欧美一二三区| 国产18精品乱码免费看| 国产欧美一区二区三区鸳鸯浴| 黑人巨大国产9丨视频| 欧美极品videos大乳护士| 欧美无人高清视频在线观看| 亚洲欧美日韩中文字幕在线观看| 免费视频国产一区| 欧美风情在线观看| 中文 欧美 日韩| 成人97人人超碰人人99| 伊人久久大香线蕉精品| 成人免费看视频网站| 制服丝袜激情欧洲亚洲| 人妻少妇精品视频一区二区三区| 91成人观看| 国产精品av在线播放| 黄色一级a毛片| 中文字幕第一区第二区| 亚洲熟妇av一区二区三区漫画| 99热这里有精品| 亚洲男人第一av网站| 欧美成人精品欧美一级私黄| 美女网站色91| 欧美三级网色| 黄毛片在线观看| 日韩欧美国产一区二区在线播放| 国产18无套直看片| 国产精品日韩| 国产伦精品一区二区三区免费视频| 午夜伦理在线| 在线免费精品视频| 一区二区三区少妇| 亚洲国产国产亚洲一二三| 114国产精品久久免费观看| 在线视频自拍| 欧美体内she精视频| 丰满圆润老女人hd| 香蕉久久国产| 久久精品国产理论片免费| 久久五月精品中文字幕| 91精品国产乱| 国产高潮国产高潮久久久91| 免费的成人av| 亚洲欧洲日夜超级视频| 亚洲成人av观看| 国产亚洲人成网站在线观看| 国产精品777777| 91在线视频免费观看| 黄色片网址在线观看| 精品国产一区二区三区成人影院| 欧美黑人xxxⅹ高潮交| 精品人妻少妇嫩草av无码专区| 亚洲女女做受ⅹxx高潮| 爱情岛论坛亚洲自拍| 亚洲精品国产偷自在线观看| 91色p视频在线| www在线视频| 日韩一级二级三级精品视频| 九九视频免费观看| 豆国产96在线|亚洲| 国产美女主播在线| aiss精品大尺度系列| 久久人人97超碰精品888| 免费观看国产精品| 狠狠躁夜夜躁人人爽天天天天97 | 日本一二三四高清不卡| 激情视频免费网站| 999久久久免费精品国产| 成人久久一区二区| 怡红院红怡院欧美aⅴ怡春院| 日韩欧美激情四射| 91精品国产乱码在线观看| 91蝌蚪porny| 国产原创精品在线| 一区二区国产在线| 国产精品久久久久久久久婷婷| 九色porny视频在线观看| 国产视频久久久久久久| 糖心vlog精品一区二区| 亚洲少妇最新在线视频| 国内自拍偷拍视频| 久久不射2019中文字幕| 午夜精品区一区二区三| 一区二区日韩| 日本韩国欧美精品大片卡二| av在线电影院| 欧美va亚洲va| 日韩精品一区不卡| 亚洲精品少妇30p| 日韩网站在线播放| 美国毛片一区二区| 隔壁人妻偷人bd中字| 小嫩嫩12欧美| 成人乱人伦精品视频在线观看| 8x8ⅹ拨牐拨牐拨牐在线观看| 香蕉久久网站| 97视频在线观看免费| av在线三区| 日韩美女在线视频| 久久久久久不卡| 一区二区三区在线视频播放| 中文字幕第4页| 国产成人久久精品77777最新版本| 免费高清在线观看免费| 在线观看免费一区二区| 免费观看成人在线| 亚洲三级电影| 国产99视频精品免视看7| 肉肉视频在线观看| 中文字幕欧美亚洲| 婷婷在线观看视频| 欧美一区二区三区四区在线观看| 五月天激情四射| 亚洲成人综合视频| 亚洲成人生活片| 国产欧美日韩激情| 国产精品久久久免费观看| 精品一区二区久久| 北条麻妃视频在线| 99亚洲视频| 好吊色视频988gao在线观看| 日韩aaaa| 欧美日韩高清免费| 人人香蕉久久| caoporn国产精品免费公开| 黄色日韩网站| 国产成人精品av| av小说在线播放| 欧美成人精品xxx| 日本不卡在线| 在线播放日韩av| 韩国三级av在线免费观看| 日韩av在线免播放器| 性中国xxx极品hd| 制服丝袜亚洲精品中文字幕| 做爰视频毛片视频| 色噜噜久久综合| 成年人视频在线免费看| 亚洲电影在线播放| 精品无码黑人又粗又大又长| 一区二区在线免费| 精品爆乳一区二区三区无码av| 1区2区3区欧美| 永久av免费网站| 亚洲欧洲日韩av| 国产真实乱在线更新| 中文字幕亚洲电影| 久久国产高清视频| 国产精品久久久久7777按摩| 免费成人深夜蜜桃视频| 久久久精品天堂| 最新中文字幕av| 国产精品女人毛片| 三级在线观看免费大全| 亚洲色图视频网站| 免费中文字幕在线观看| 亚洲国产美女搞黄色| 国产成人在线免费视频| 日韩欧美精品网址| 无码人妻精品一区二| 欧美色视频在线| 一区二区三区www污污污网站| 91精品国产91热久久久做人人| 国产精品无码久久久久成人app| 欧美一区二区三区免费观看视频 | 亚洲精品大尺度| 青青青草原在线| 神马久久久久久| 影音先锋男人在线资源| 97色在线视频观看| 中文字幕资源网在线观看免费 | 凹凸成人精品亚洲精品密奴| 亚洲欧美国产不卡| 欧美日本一区| 国模吧无码一区二区三区| 日韩精品1区2区3区| 亚洲综合日韩欧美| 国产精品66部| 中文字幕一区二区三区人妻| 国产精品嫩草99a| 免费在线观看亚洲| 色婷婷久久久综合中文字幕| 一级久久久久久久| 亚洲精品一区二区精华| 超碰国产在线| 欧美激情在线视频二区| 欧美电影免费观看| 亚洲999一在线观看www| 天天做夜夜做人人爱精品| 在线观看欧美亚洲| 亚洲毛片在线| 九九精品久久久| 成人精品视频网站| 免费看的黄色录像| 亚洲成人一区在线| 在线免费观看一区二区| 亚洲第一视频在线观看| www.91在线| 91干在线观看| 国产一区二区三区免费观看在线| 六十路精品视频| 午夜精品婷婷| 成人午夜激情av| 北岛玲一区二区三区四区| 精品女人久久久| 日韩欧美在线观看| 亚洲精品网站在线| 中文字幕无线精品亚洲乱码一区 | 右手影院亚洲欧美| 亚洲女与黑人做爰| 中文字幕在线观看国产| 亚洲精品网址在线观看| 成人福利在线观看视频| 国产精品∨欧美精品v日韩精品| 国产精品zjzjzj在线观看| 在线观看日韩片| 日韩精品1区2区3区| 亚洲欧美色图视频| 亚洲一区欧美一区| 国产91视频在线| 一区二区亚洲欧洲国产日韩| 极品在线视频| 超碰在线97av| 综合av在线| 国产农村妇女精品久久| 国产精品福利一区二区三区| 麻豆成人免费视频| 日韩av在线一区| 999福利在线视频| 成人91视频| 欧美午夜不卡| 原创真实夫妻啪啪av| 亚洲欧洲av在线| 91精品国产乱码久久久| 一区二区欧美日韩视频| 国产精品迅雷| 日本一区二区三区在线视频| 国产一区二区三区久久久久久久久 | 忘忧草在线日韩www影院| 成人欧美一区二区三区在线观看| 欧美一区不卡| 俄罗斯女人裸体性做爰| 一区二区三区欧美日| 精品久久久久中文慕人妻| 久久精品国产亚洲7777| 99精品国产九九国产精品| 五月天av影院| 国产一区二区在线免费观看| 尤物在线免费视频| 91麻豆精品国产91久久久久久久久 | 91热这里只有精品| 国产精品欧美精品| 一本一道精品欧美中文字幕| 久久九九有精品国产23| 国产剧情一区二区在线观看| 日本一二三区视频在线| 国产传媒欧美日韩成人| 不卡的免费av| 亚洲免费一级电影| av在线一区不卡| 人人妻人人澡人人爽精品欧美一区| 国产一区二区三区日韩| 欧美成人精品激情在线视频| 精品粉嫩aⅴ一区二区三区四区| 51漫画成人app入口| 欧美亚洲免费高清在线观看| 青青草91视频| 波多野结衣不卡视频| 亚洲成色777777女色窝| 在线看片福利| 色播五月综合| 国产成人综合在线| 国产无码精品在线播放| 日韩精品在线免费| 色成人免费网站| 国产亚洲精品久久久久久久| 成a人片国产精品| wwwwww在线观看| 欧美超级免费视 在线| 欧美成a人免费观看久久| 久草在在线视频| 亚洲欧美成aⅴ人在线观看| 色窝窝无码一区二区三区| 国产精品激情自拍| 你懂的国产精品永久在线| 精品黑人一区二区三区观看时间| 欧美在线啊v一区| 国产丝袜在线播放| 日韩欧美在线一区二区| 成人自拍视频在线观看| 青青艹在线观看| 久久99久国产精品黄毛片入口| 国产成人ay| 少妇极品熟妇人妻无码| 91福利资源站| 美女尤物在线视频| 午夜精品短视频| 不卡的av在线| 国产精品高潮呻吟AV无码| 91精品国产九九九久久久亚洲| 五月婷婷亚洲| a级大片在线观看| 精品国产污污免费网站入口| 国产福利一区二区三区在线播放| 亚洲理论电影在线观看|