精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

日韩一区二区免费电影| 91亚洲大成网污www| 中文字幕亚洲专区| 欧美大尺度做爰床戏| fc2在线中文字幕| 黄色亚洲在线| 日韩不卡中文字幕| 日本三区在线观看| 思思99re6国产在线播放| 久久精品免费观看| 欧美成年人视频网站| 欧美xxxx日本和非洲| 91超碰在线播放| 91蜜桃婷婷狠狠久久综合9色| 日本国产精品视频| 国产欧美一区二区视频| 免费在线观看一级片| 美女日韩一区| 精品高清美女精品国产区| 久久av免费观看| 久久久久久亚洲av无码专区| 久久一本综合| 日韩欧美国产三级| 免费高清在线观看免费| www.在线视频.com| 国产精品中文字幕日韩精品| 91国在线精品国内播放| 日本黄色小视频在线观看| 永久免费观看精品视频| 亚洲成人7777| 日韩一区二区电影在线观看| 国产高清在线免费| 美女被久久久| 久久国产加勒比精品无码| 在线观看国产免费视频| 欧美天堂一区| 午夜亚洲福利老司机| 日本午夜精品电影 | 欧美视频国产精品| 亚洲第一精品区| 国产国语亲子伦亲子| 丝袜脚交一区二区| 欧美丰满少妇xxxxx做受| 亚洲香蕉中文网| 91看片一区| 亚洲高清在线视频| 中文字幕在线中文字幕日亚韩一区 | 中文字幕不卡av| 中文字幕在线视频播放| 免费高清视频在线一区| 午夜欧美2019年伦理| 成年人三级视频| 九九在线视频| www.日韩在线| eeuss一区二区三区| 又污又黄的网站| 国产精品日本| 久久久免费精品| 黄色片子在线观看| 日韩精品免费| 亚洲一品av免费观看| bl动漫在线观看| 日韩区一区二| 欧美日韩激情一区二区三区| 男女av免费观看| 超碰人人在线| 亚洲视频资源在线| 水蜜桃一区二区三区| 亚洲欧美一区二区三| 丁香婷婷综合网| 91原创国产| 国产伦一区二区| 麻豆极品一区二区三区| 国产精品pans私拍| 久久久国产高清| 亚洲一级高清| 国语自产偷拍精品视频偷| 18岁成人毛片| 色综合久久网| 最近中文字幕日韩精品| 五月婷婷欧美激情| 欧美一区电影| 中文亚洲视频在线| 91香蕉视频网| 97欧美在线视频| zzijzzij亚洲日本成熟少妇| 91香蕉国产视频| av亚洲在线观看| 伊人成人开心激情综合网| 特大黑人巨人吊xxxx| 国产精品自在| 日韩成人在线网站| 欧美熟妇一区二区| 欧美少妇性xxxx| 日韩在线观看高清| 国产又粗又长免费视频| 亚洲激情久久| 欧美国产日韩在线| 日韩精品视频播放| 国产日韩欧美在线播放不卡| 日韩av免费看网站| 中文字幕激情视频| 狠狠久久亚洲欧美| 风间由美久久久| 天天综合网天天综合| 国产日韩欧美精品在线| 一区二区三区我不卡| 蜜桃视频网站在线| 亚洲一区二区在线视频| 99精品人妻少妇一区二区| 亚洲伦乱视频| 337p亚洲精品色噜噜噜| 九九九九精品九九九九| 亚洲免费观看高清完整版在线| 日韩精品一区二区久久| 国产精品天堂蜜av在线播放| 亚洲日本中文字幕区| 欧美这里只有精品| 亚洲欧洲美洲av| 欧美日韩久久一区| 国产精品99精品无码视亚| 日韩av字幕| 日韩小视频在线观看| 久久久精品视频免费| 日韩av不卡一区二区| 97在线中文字幕| 国产一级在线| 亚洲影视在线播放| 国产又黄又猛又粗又爽的视频| 嫩草伊人久久精品少妇av杨幂| 欧美一级片在线看| 在线观看亚洲免费视频| 首页国产精品| 97国产suv精品一区二区62| 中文字幕人妻一区二区在线视频| 成人中文字幕在线| 最新不卡av| 手机看片久久| 精品成人一区二区三区| 天堂资源在线视频| 国产婷婷精品| 鬼打鬼之黄金道士1992林正英| 国产三区四区在线观看| 亚洲国产美女搞黄色| 亚洲一区二区偷拍| 精品国产一区二区三区小蝌蚪 | 亚洲女同志亚洲女同女播放| 国产视频一区二区在线| 性一交一乱一伧国产女士spa| 免费日韩成人| 亚洲欧美日韩中文在线制服| 久久中文字幕无码| 久久99精品国产麻豆不卡| 欧美人与物videos另类| 成人福利电影| 日韩无一区二区| 特级西西人体高清大胆| 久久久久国产一区二区| 国精产品99永久一区一区| 日韩伦理av| 亚洲国产成人精品女人久久久| 久草视频精品在线| 91年精品国产| 精品视频无码一区二区三区| av亚洲免费| 成人欧美一区二区三区黑人| 黄色网页在线看| 日韩精品中文字幕在线不卡尤物| 欧美精品一区二区蜜桃| eeuss鲁片一区二区三区在线观看| 一二三四视频社区在线| 日韩免费电影在线观看| 国产精品成熟老女人| 在线观看国产原创自拍视频| 制服丝袜av成人在线看| 久久久久无码国产精品不卡| 波多野结衣在线一区| 无码人妻丰满熟妇区五十路百度| jlzzjlzz亚洲女人| 91免费版网站入口| 国产理论在线| 一个色综合导航| 国产熟女一区二区三区四区| 亚洲高清不卡在线观看| 欧美多人猛交狂配| 国产自产视频一区二区三区| 国产二区视频在线| 国产综合久久久| 亚洲a中文字幕| √天堂8资源中文在线| 亚洲欧洲午夜一线一品| 伊人网视频在线| 亚洲一区二区欧美激情| av电影在线不卡| 国产麻豆视频一区| 韩国日本在线视频| 欧美一区高清| 欧美日韩一区二区视频在线观看| 亚洲爽爆av| 4p变态网欧美系列| 大片免费在线观看| 亚洲男人第一av网站| 国产理论视频在线观看| 亚洲成人av一区二区| 91制片厂在线| 99re成人精品视频| 日本一二三区在线| 日韩中文字幕麻豆| 欧美午夜小视频| 99精品视频在线| 久热这里只精品99re8久| 国产一区二区三区免费在线| 国产91免费看片| 大香伊人中文字幕精品| 中文字幕视频在线免费欧美日韩综合在线看 | 午夜天堂精品久久久久| 日韩欧美精品在线不卡| 久久男人av| 亚洲mm色国产网站| 福利一区和二区| 欧美亚洲另类制服自拍| 手机在线免费av| 日韩中文第一页| 黄色网址在线播放| 亚洲国产欧美一区二区丝袜黑人| 国产巨乳在线观看| 欧美午夜一区二区三区| 美女又爽又黄免费视频| 亚洲国产综合色| 日韩一区二区三区四区在线| 中文字幕在线一区| 日本黄色小视频在线观看| 久久只精品国产| 国产精品成人99一区无码| 国产精品综合二区| 黄色手机在线视频| 日韩激情中文字幕| aaa毛片在线观看| 久久久久网站| 麻豆av免费在线| 美女视频一区免费观看| 丰满爆乳一区二区三区| 国产欧美欧美| 人妻熟妇乱又伦精品视频| 精品96久久久久久中文字幕无| 777久久精品一区二区三区无码 | 国产精品18久久久久久久久久久久 | 亚洲色图第四色| 日本一区二区综合亚洲| jizz中文字幕| 亚洲国产高清aⅴ视频| 少妇一级黄色片| 国产精品久久久久久久久果冻传媒| 人妻一区二区视频| 中文字幕欧美激情一区| 国产欧美一区二区三区在线观看视频| 国产视频视频一区| 国产18无套直看片| 中文字幕亚洲一区二区av在线| 91麻豆精品久久毛片一级| 亚洲欧美综合在线精品| 国产一区二区视频在线观看免费| 亚洲美女区一区| 国产在线综合网| 精品国产91久久久久久| 一区二区三区在线观看av| 在线观看免费视频综合| 在线黄色av网站| 91精品国产综合久久香蕉麻豆| jlzzjlzz亚洲女人18| 精品人在线二区三区| 无码国产伦一区二区三区视频| 国产丝袜一区视频在线观看| 成人免费一区二区三区视频网站| 一区国产精品视频| 深夜国产在线播放| 日本精品视频在线| 亚洲日本免费电影| 超碰97在线人人| 外国成人在线视频| 伊人狠狠色丁香综合尤物| 欧美高清不卡| 精品中文字幕av| 久久精品999| www.555国产精品免费| 久久久蜜桃精品| 久久精品一区二区三区四区五区| 亚洲午夜一区二区三区| 国产午夜无码视频在线观看| 日韩一区二区三区在线观看| 青青草超碰在线| 久久国产精品影视| 亚洲美女尤物影院| 91精品国产综合久久香蕉最新版| 99久久免费精品国产72精品九九| 蜜桃传媒视频麻豆第一区免费观看| 日韩成人激情| 美女日批免费视频| 美女精品一区二区| 李丽珍裸体午夜理伦片| 国产精品久久久久久久久搜平片| 国产真实夫妇交换视频| 欧美在线观看视频一区二区| av av片在线看| 亚洲天堂视频在线观看| 国产精品探花在线| 国产欧美一区二区三区久久人妖| 国产精品调教视频| 懂色av一区二区三区四区五区| 国产日产高清欧美一区二区三区| 毛片毛片毛片毛| 久久久久国产精品麻豆| 国产无码精品一区二区| 欧美日本一区二区三区| 欧美新色视频| 欧美国产激情18| 9999精品视频| 午夜午夜精品一区二区三区文| 亚洲黄色影院| 免费高清视频在线观看| 国产欧美精品在线观看| 综合激情网五月| 欧美成人激情免费网| 久操视频在线| 国产精品久久久久久av福利软件 | 欧美mv日韩mv亚洲| 免费成人黄色| 国产精品视频永久免费播放| 精品国产影院| 欧美中文字幕在线观看视频 | 欧美日韩亚洲高清| 狠狠躁夜夜躁av无码中文幕| 久久中文字幕在线| 色综合视频一区二区三区日韩 | 性猛交╳xxx乱大交| ㊣最新国产の精品bt伙计久久| 这里只有久久精品视频| 亚洲人成电影在线观看天堂色| 黄色视屏在线免费观看| 国产伦精品一区二区三区| 欧美日本一区二区高清播放视频| 一二三级黄色片| 一色桃子久久精品亚洲| 亚洲视频一区在线播放| 伊人av综合网| 日韩国产大片| 黄瓜视频免费观看在线观看www | 国产精品福利在线观看播放| 最新中文字幕免费视频| 中文字幕第一区二区| 最近中文字幕免费观看| 一区二区三区视频免费| 日韩精品第一| 在线观看欧美激情| 狠狠色丁香九九婷婷综合五月| 国产成人av免费在线观看| 91精品国产入口在线| a级毛片免费观看在线| 91成人免费看| 亚洲经典自拍| 亚洲最大的黄色网| 色哟哟一区二区三区| av在线第一页| 成人免费黄色网| 欧美日韩网站| 自拍视频一区二区| 色八戒一区二区三区| 日本中文字幕在线视频| 亚洲va国产va天堂va久久| 在线成人欧美| av黄色免费网站| 欧美日韩精品一区二区三区四区 | www.久久精品.com| 97热精品视频官网| 欧美日本成人| 精品久久久99| 亚洲一区在线观看视频| 神马亚洲视频| 国产精品中文字幕久久久| 欧美不卡在线| 97伦伦午夜电影理伦片| 欧美日韩dvd在线观看| 国产经典三级在线| 欧美日韩高清在线一区| 理论片日本一区| 国产主播在线观看| 亚洲网址你懂得| 免费观看性欧美大片无片| 亚洲熟妇无码另类久久久| 日本一区二区动态图| www夜片内射视频日韩精品成人| **欧美日韩vr在线| 精品视频黄色| 久久久久亚洲av片无码v| 欧美日韩亚洲视频| 国产在线观看免费麻豆| 欧美日韩综合另类| 国产成人av电影在线| 久久国产香蕉视频| 久久久亚洲成人|