成人性生交大片免费看视频r_亚洲综合极品香蕉久久网_在线视频免费观看一区_亚洲精品亚洲人成人网在线播放_国产精品毛片av_久久久久国产精品www_亚洲国产一区二区三区在线播_日韩一区二区三区四区区区_亚洲精品国产无套在线观_国产免费www

主頁 > 知識庫 > 詳解Go語言RESTful JSON API創(chuàng)建

詳解Go語言RESTful JSON API創(chuàng)建

熱門標(biāo)簽:鄭州亮點科技用的什么外呼系統(tǒng) 釘釘有地圖標(biāo)注功能嗎 建造者2地圖標(biāo)注 黃岡人工智能電銷機(jī)器人哪個好 汕頭小型外呼系統(tǒng) 阿里云ai電話機(jī)器人 濱州自動電銷機(jī)器人排名 浙江高頻外呼系統(tǒng)多少錢一個月 惠州電銷防封電話卡

RESTful API在Web項目開發(fā)中廣泛使用,本文針對Go語言如何一步步實現(xiàn)RESTful JSON API進(jìn)行講解, 另外也會涉及到RESTful設(shè)計方面的話題。

也許我們之前有使用過各種各樣的API, 當(dāng)我們遇到設(shè)計很糟糕的API的時候,簡直感覺崩潰至極。希望通過本文之后,能對設(shè)計良好的RESTful API有一個初步認(rèn)識。

JSON API是什么?

JSON之前,很多網(wǎng)站都通過XML進(jìn)行數(shù)據(jù)交換。如果在使用過XML之后,再接觸JSON, 毫無疑問,你會覺得世界多么美好。這里不深入JSON API的介紹,有興趣可以參考jsonapi。

基本的Web服務(wù)器

從根本上講,RESTful服務(wù)首先是Web服務(wù)。 因此我們可以先看看Go語言中基本的Web服務(wù)器是如何實現(xiàn)的。下面例子實現(xiàn)了一個簡單的Web服務(wù)器,對于任何請求,服務(wù)器都響應(yīng)請求的URL回去。

package main

import (
  "fmt"
  "html"
  "log"
  "net/http"
)

func main() {
  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
  })

  log.Fatal(http.ListenAndServe(":8080", nil))
}

上面基本的web服務(wù)器使用Go標(biāo)準(zhǔn)庫的兩個基本函數(shù)HandleFunc和ListenAndServe。

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
  DefaultServeMux.HandleFunc(pattern, handler)
}

func ListenAndServe(addr string, handler Handler) error {
  server := Server{Addr: addr, Handler: handler}
  return server.ListenAndServe()
}

運(yùn)行上面的基本web服務(wù),就可以直接通過瀏覽器訪問http://localhost:8080來訪問。

> go run basic_server.go

添加路由

雖然標(biāo)準(zhǔn)庫包含有router, 但是我發(fā)現(xiàn)很多人對它的工作原理感覺很困惑。 我在自己的項目中使用過各種不同的第三方router庫。 最值得一提的是Gorilla Web ToolKit的mux router。

另外一個流行的router是來自Julien Schmidt的叫做httprouter的包。

package main

import (
  "fmt"
  "html"
  "log"
  "net/http"

  "github.com/gorilla/mux"
)

func main() {
  router := mux.NewRouter().StrictSlash(true)
  router.HandleFunc("/", Index)

  log.Fatal(http.ListenAndServe(":8080", router))
}

func Index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}

要運(yùn)行上面的代碼,首先使用go get獲取mux router的源代碼:

> go get github.com/gorilla/mux

上面代碼創(chuàng)建了一個基本的路由器,給請求"/"賦予Index處理器,當(dāng)客戶端請求http://localhost:8080/的時候,就會執(zhí)行Index處理器。

如果你足夠細(xì)心,你會發(fā)現(xiàn)之前的基本web服務(wù)訪問http://localhost:8080/abc能正常響應(yīng): 'Hello, "/abc"', 但是在添加了路由之后,就只能訪問http://localhost:8080了。 原因很簡單,因為我們只添加了對"/"的解析,其他的路由都是無效路由,因此都是404。

創(chuàng)建一些基本的路由

既然我們加入了路由,那么我們就可以再添加更多路由進(jìn)來了。

假設(shè)我們要創(chuàng)建一個基本的ToDo應(yīng)用, 于是我們的代碼就變成下面這樣:

package main

import (
  "fmt"
  "log"
  "net/http"

  "github.com/gorilla/mux"
)

func main() {
  router := mux.NewRouter().StrictSlash(true)
  router.HandleFunc("/", Index)
  router.HandleFunc("/todos", TodoIndex)
  router.HandleFunc("/todos/{todoId}", TodoShow)

  log.Fatal(http.ListenAndServe(":8080", router))
}

func Index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Welcome!")
}

func TodoIndex(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Todo Index!")
}

func TodoShow(w http.ResponseWriter, r *http.Request) {
  vars := mux.Vars(r)
  todoId := vars["todoId"]
  fmt.Fprintln(w, "Todo Show:", todoId)
}

在這里我們添加了另外兩個路由: todos和todos/{todoId}。

這就是RESTful API設(shè)計的開始。

請注意最后一個路由我們給路由后面添加了一個變量叫做todoId。

這樣就允許我們傳遞id給路由,并且能使用具體的記錄來響應(yīng)請求。

基本模型

路由現(xiàn)在已經(jīng)就緒,是時候創(chuàng)建Model了,可以用model發(fā)送和檢索數(shù)據(jù)。在Go語言中,model可以使用結(jié)構(gòu)體來實現(xiàn),而其他語言中model一般都是使用類來實現(xiàn)。

package main

import (
  "time"
)

type Todo struct {
  Name   string
  Completed bool
  Due    time.Time
}

type Todos []Todo

上面我們定義了一個Todo結(jié)構(gòu)體,用于表示待做項。 另外我們還定義了一種類型Todos, 它表示待做列表,是一個數(shù)組,或者說是一個分片。

稍后你就會看到這樣會變得非常有用。

返回一些JSON

我們有了基本的模型,那么我們可以模擬一些真實的響應(yīng)了。我們可以為TodoIndex模擬一些靜態(tài)的數(shù)據(jù)列表。

package main

import (
  "encoding/json"
  "fmt"
  "log"
  "net/http"

  "github.com/gorilla/mux"
)

// ...

func TodoIndex(w http.ResponseWriter, r *http.Request) {
  todos := Todos{
    Todo{Name: "Write presentation"},
    Todo{Name: "Host meetup"},
  }

  json.NewEncoder(w).Encode(todos)
}

// ...

現(xiàn)在我們創(chuàng)建了一個靜態(tài)的Todos分片來響應(yīng)客戶端請求。注意,如果你請求http://localhost:8080/todos, 就會得到下面的響應(yīng):

[
  {
    "Name": "Write presentation",
    "Completed": false,
    "Due": "0001-01-01T00:00:00Z"
  },
  {
    "Name": "Host meetup",
    "Completed": false,
    "Due": "0001-01-01T00:00:00Z"
  }
]

更好的Model

對于經(jīng)驗豐富的老兵來說,你可能已經(jīng)發(fā)現(xiàn)了一個問題。響應(yīng)JSON的每個key都是首字母答寫的,雖然看起來微不足道,但是響應(yīng)JSON的key首字母大寫不是習(xí)慣的做法。 那么下面教你如何解決這個問題:

type Todo struct {
  Name   string  `json:"name"`
  Completed bool   `json:"completed"`
  Due    time.Time `json:"due"`
}

其實很簡單,就是在結(jié)構(gòu)體中添加標(biāo)簽屬性, 這樣可以完全控制結(jié)構(gòu)體如何編排(marshalled)成JSON。

拆分代碼

到目前為止,我們所有代碼都在一個文件中。顯得雜亂, 是時候拆分代碼了。我們可以將代碼按照功能拆分成下面多個文件。

我們準(zhǔn)備創(chuàng)建下面的文件,然后將相應(yīng)代碼移到具體的代碼文件中:

  1. main.go: 程序入口文件。
  2. handlers.go: 路由相關(guān)的處理器。
  3. routes.go: 路由。
  4. todo.go: todo相關(guān)的代碼。
package main

import (
  "encoding/json"
  "fmt"
  "net/http"

  "github.com/gorilla/mux"
)

func Index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Welcome!")
}

func TodoIndex(w http.ResponseWriter, r *http.Request) {
  todos := Todos{
    Todo{Name: "Write presentation"},
    Todo{Name: "Host meetup"},
  }

  if err := json.NewEncoder(w).Encode(todos); err != nil {
    panic(err)
  }
}

func TodoShow(w http.ResponseWriter, r *http.Request) {
  vars := mux.Vars(r)
  todoId := vars["todoId"]
  fmt.Fprintln(w, "Todo show:", todoId)
}
package main

import (
  "net/http"

  "github.com/gorilla/mux"
)

type Route struct {
  Name    string
  Method   string
  Pattern   string
  HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {

  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(route.HandlerFunc)
  }

  return router
}

var routes = Routes{
  Route{
    "Index",
    "GET",
    "/",
    Index,
  },
  Route{
    "TodoIndex",
    "GET",
    "/todos",
    TodoIndex,
  },
  Route{
    "TodoShow",
    "GET",
    "/todos/{todoId}",
    TodoShow,
  },
}

package main

import "time"

type Todo struct {
  Name   string  `json:"name"`
  Completed bool   `json:"completed"`
  Due    time.Time `json:"due"`
}

type Todos []Todo
package main
import (
  "log"
  "net/http"
)

func main() {
  router := NewRouter()
  log.Fatal(http.ListenAndServe(":8080", router))
}

更好的Routing

我們重構(gòu)的過程中,我們創(chuàng)建了一個更多功能的routes文件。 這個新文件利用了一個包含多個關(guān)于路由信息的結(jié)構(gòu)體。 注意,這里我們可以指定請求的類型,例如GET, POST, DELETE等等。

輸出Web日志

在拆分的路由文件中,我也包含有一個不可告人的動機(jī)。稍后你就會看到,拆分之后很容易使用另外的函數(shù)來修飾http處理器。

首先我們需要有對web請求打日志的能力,就像很多流行web服務(wù)器那樣的。 在Go語言中,標(biāo)準(zhǔn)庫里邊沒有web日志包或功能, 因此我們需要自己創(chuàng)建。

package logger
import (
  "log"
  "net/http"
  "time"
)

func Logger(inner http.Handler, name string) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    start := time.Now()
    inner.ServeHTTP(w, r)
    log.Printf(
      "%s\t%s\t%s\t%s",
      r.Method,
      r.RequestURI,
      name,
      time.Since(start),
    )
  })
}

上面我們定義了一個Logger函數(shù),可以給handler進(jìn)行包裝修飾。

這是Go語言中非常標(biāo)準(zhǔn)的慣用方式。其實也是函數(shù)式編程的慣用方式。 非常有效,我們只需要將Handler傳入該函數(shù), 然后它會將傳入的handler包裝一下,添加web日志和耗時統(tǒng)計功能。

應(yīng)用Logger修飾器

要應(yīng)用Logger修飾符, 我們可以創(chuàng)建router, 我們只需要簡單的將我們所有的當(dāng)前路由都包到其中, NewRouter函數(shù)修改如下:

func NewRouter() *mux.Router {

  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    var handler http.Handler

    handler = route.HandlerFunc
    handler = Logger(handler, route.Name)

    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(handler)
  }

  return router
}

現(xiàn)在再次運(yùn)行我們的程序,我們就可以看到日志大概如下:

2014/11/19 12:41:39 GET /todos TodoIndex 148.324us

這個路由文件太瘋狂...讓我們重構(gòu)它吧

路由routes文件現(xiàn)在已經(jīng)變得稍微大了些, 下面我們將它分解成多個文件:

  1. routes.go
  2. router.go
package main

import "net/http"

type Route struct {
  Name    string
  Method   string
  Pattern   string
  HandlerFunc http.HandlerFunc
}

type Routes []Route

var routes = Routes{
  Route{
    "Index",
    "GET",
    "/",
    Index,
  },
  Route{
    "TodoIndex",
    "GET",
    "/todos",
    TodoIndex,
  },
  Route{
    "TodoShow",
    "GET",
    "/todos/{todoId}",
    TodoShow,
  },
}

package main

import (
  "net/http"

  "github.com/gorilla/mux"
)

func NewRouter() *mux.Router {
  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    var handler http.Handler
    handler = route.HandlerFunc
    handler = Logger(handler, route.Name)

    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(handler)

  }
  return router
}

另外再承擔(dān)一些責(zé)任

到目前為止,我們已經(jīng)有了一些相當(dāng)好的樣板代碼(boilerplate), 是時候重新審視我們的處理器了。我們需要稍微多的責(zé)任。 首先修改TodoIndex,添加下面兩行代碼:

func TodoIndex(w http.ResponseWriter, r *http.Request) {
  todos := Todos{
    Todo{Name: "Write presentation"},
    Todo{Name: "Host meetup"},
  }
  w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  w.WriteHeader(http.StatusOK)
  if err := json.NewEncoder(w).Encode(todos); err != nil {
    panic(err)
  }
}

這里發(fā)生了兩件事。 首先,我們設(shè)置了響應(yīng)類型并告訴客戶端期望接受JSON。第二,我們明確的設(shè)置了響應(yīng)狀態(tài)碼。

Go語言的net/http服務(wù)器會嘗試為我們猜測輸出內(nèi)容類型(然而并不是每次都準(zhǔn)確的), 但是既然我們已經(jīng)確切的知道響應(yīng)類型,我們總是應(yīng)該自己設(shè)置它。

稍等片刻,我們的數(shù)據(jù)庫在哪里?

很明顯,如果我們要創(chuàng)建RESTful API, 我們需要一些用于存儲和檢索數(shù)據(jù)的地方。然而,這個是不是本文的范圍之內(nèi), 因此我們將簡單的創(chuàng)建一個非常簡陋的模擬數(shù)據(jù)庫(非線程安全的)。

我們創(chuàng)建一個repo.go文件,內(nèi)容如下:

package main

import "fmt"

var currentId int

var todos Todos

// Give us some seed data
func init() {
  RepoCreateTodo(Todo{Name: "Write presentation"})
  RepoCreateTodo(Todo{Name: "Host meetup"})
}

func RepoFindTodo(id int) Todo {
  for _, t := range todos {
    if t.Id == id {
      return t
    }
  }
  // return empty Todo if not found
  return Todo{}
}

func RepoCreateTodo(t Todo) Todo {
  currentId += 1
  t.Id = currentId
  todos = append(todos, t)
  return t
}
func RepoDestroyTodo(id int) error {
  for i, t := range todos {
    if t.Id == id {
      todos = append(todos[:i], todos[i+1:]...)
      return nil
    }
  }
  return fmt.Errorf("Could not find Todo with id of %d to delete", id)
}

給Todo添加ID

我們創(chuàng)建了模擬數(shù)據(jù)庫,我們使用并賦予id, 因此我們相應(yīng)的也需要更新我們的Todo結(jié)構(gòu)體。

package main
import "time"
type Todo struct {
  Id    int    `json:"id"`
  Name   string  `json:"name"`
  Completed bool   `json:"completed"`
  Due    time.Time `json:"due"`
}
type Todos []Todo

更新我們的TodoIndex

要使用數(shù)據(jù)庫,我們需要在TodoIndex中檢索數(shù)據(jù)。修改代碼如下:

func TodoIndex(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  w.WriteHeader(http.StatusOK)
  if err := json.NewEncoder(w).Encode(todos); err != nil {
    panic(err)
  }
}


POST JSON

到目前為止,我們只是輸出JSON, 現(xiàn)在是時候進(jìn)入存儲一些JSON了。

在routes.go文件中添加如下路由:

Route{
  "TodoCreate",
  "POST",
  "/todos",
  TodoCreate,
},

Create路由

func TodoCreate(w http.ResponseWriter, r *http.Request) {
  var todo Todo
  body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
  if err != nil {
    panic(err)
  }
  if err := r.Body.Close(); err != nil {
    panic(err)
  }
  if err := json.Unmarshal(body, todo); err != nil {
    w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.WriteHeader(422) // unprocessable entity
    if err := json.NewEncoder(w).Encode(err); err != nil {
      panic(err)
    }
  }

  t := RepoCreateTodo(todo)
  w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  w.WriteHeader(http.StatusCreated)
  if err := json.NewEncoder(w).Encode(t); err != nil {
    panic(err)
  }
}

首先我們打開請求的body。 注意我們使用io.LimitReader。這樣是保護(hù)服務(wù)器免受惡意攻擊的好方法。假設(shè)如果有人想要給你服務(wù)器發(fā)送500GB的JSON怎么辦?

我們讀取body以后,我們解構(gòu)Todo結(jié)構(gòu)體。 如果失敗,我們作出正確的響應(yīng),使用恰當(dāng)?shù)捻憫?yīng)碼422, 但是我們依然使用json響應(yīng)回去。 這樣可以允許客戶端理解有錯發(fā)生了, 而且有辦法知道到底發(fā)生了什么錯誤。

最后,如果所有都通過了,我們就響應(yīng)201狀態(tài)碼,表示請求創(chuàng)建的實體已經(jīng)成功創(chuàng)建了。 我們同樣還是響應(yīng)回代表我們創(chuàng)建的實體的json, 它會包含一個id, 客戶端可能接下來需要用到它。

POST一些JSON

我們現(xiàn)在有了偽repo, 也有了create路由,那么我們需要post一些數(shù)據(jù)。 我們使用curl通過下面的命令來達(dá)到這個目的:

復(fù)制代碼 代碼如下:
curl -H "Content-Type: application/json" -d '{"name": "New Todo"}' http://localhost:8080/todos

如果你再次通過http://localhost:8080/todos訪問,大概會得到下面的響應(yīng):

[
  {
    "id": 1,
    "name": "Write presentation",
    "completed": false,
    "due": "0001-01-01T00:00:00Z"
  },
  {
    "id": 2,
    "name": "Host meetup",
    "completed": false,
    "due": "0001-01-01T00:00:00Z"
  },
  {
    "id": 3,
    "name": "New Todo",
    "completed": false,
    "due": "0001-01-01T00:00:00Z"
  }
]

我們還沒有做的事情

雖然我們已經(jīng)有了很好的開端,但是還有很多事情沒有做:

  1. 版本控制: 如果我們需要修改API, 結(jié)果完全改變了怎么辦? 可能我們需要在我們的路由開頭加上/v1/prefix?
  2. 授權(quán): 除非這些都是公開/免費(fèi)API, 我們可能還需要授權(quán)。 建議學(xué)習(xí)JSON web tokens的東西。

eTag - 如果你正在構(gòu)建一些需要擴(kuò)展的東西,你可能需要實現(xiàn)eTag。

還有什么?

對于所有項目來說,開始都很小,但是很快就變得失控了。但是如果我們想要將它帶到另外一個層次, 讓他生產(chǎn)就緒, 還有一些額外的事情需要做:

  1. 大量重構(gòu)(refactoring).
  2. 為這些文件創(chuàng)建幾個包,例如一些JSON助手、修飾符、處理器等等。
  3. 測試, 使得,你不能忘記這點。這里我們沒有做任何測試。對于生產(chǎn)系統(tǒng)來說,測試是必須的。

源代碼:https://github.com/corylanou/tns-restful-json-api

總結(jié)

對我來說,最重要的,需要記住的是我們要建立一個負(fù)責(zé)任的API。 發(fā)送適當(dāng)?shù)臓顟B(tài)碼,header等,這些是API廣泛采用的關(guān)鍵。我希望本文能讓你盡快開始自己的API。

參考鏈接

Go語言RESTful JSON API實現(xiàn)
JSON API
Gorilla Web Toolkit
httprouter
JSON Web Tokens
eTag

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • Django開發(fā)RESTful API實現(xiàn)增刪改查(入門級)
  • go 原生http web 服務(wù)跨域restful api的寫法介紹
  • Django restful framework生成API文檔過程詳解
  • Django JWT Token RestfulAPI用戶認(rèn)證詳解
  • Python利用Django如何寫restful api接口詳解
  • 詳解Django rest_framework實現(xiàn)RESTful API
  • 基于Go語言構(gòu)建RESTful API服務(wù)

標(biāo)簽:瀘州 阿壩 晉中 泰安 東營 滄州 駐馬店 昭通

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《詳解Go語言RESTful JSON API創(chuàng)建》,本文關(guān)鍵詞  詳解,語言,RESTful,JSON,API,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《詳解Go語言RESTful JSON API創(chuàng)建》相關(guān)的同類信息!
  • 本頁收集關(guān)于詳解Go語言RESTful JSON API創(chuàng)建的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    婷婷免费在线视频| 精选一区二区三区四区五区| 91精品视频网站| 一区二区在线观| 日韩在线观看av| 人妻激情偷乱视频一区二区三区| 国产欧美在线观看| 黑人与娇小精品av专区| 在线日韩中文| 激情综合网五月天| 亚洲第一网站男人都懂| 亚洲精品久久| 日本一区视频在线观看免费| 女生裸体免费视频| 在线观看视频一区二区三区| 国产亚洲欧美一级| 日韩黄色在线免费观看| 日韩一区二区三区视频在线观看| 欧美不卡在线一区二区三区| 国产精品一区在线观看| 成人av男人的天堂| 免费一级做a爰片久久毛片潮| 欧美在线观看网站| 欧美日韩视频免费| 天天色天天爽| 高清日韩av电影| 国产欧美婷婷中文| 这里有精品可以观看| 国产高清视频一区| 中文在线最新版天堂| 影音先锋男人资源在线观看| 婷婷久久综合九色综合伊人色| 亚洲成熟少妇视频在线观看| 中文字幕亚洲一区二区va在线| 高清全集视频免费在线| 国产精品欧美风情| 麻豆福利在线观看| 欧美第一页在线| 欧美日韩另类字幕中文| 黄色片视频免费| 亚洲第一色视频| 91蝌蚪porny九色| 亚洲跨种族黑人xxx| 不卡av在线网站| 日韩福利一区二区| 色综合天天综合网国产成人网| 日本中文字幕网| 91高清在线观看视频| 国精一区二区三区| 永久免费在线看片视频| 日韩毛片在线播放| 97在线免费视频观看| 国内av免费| 国产精品久久久久久久久久直播| 国产欧美一区二区| 欧美激情成人网| 日本成人在线不卡视频| 天堂va欧美ⅴa亚洲va一国产| yourporn在线观看中文站| 精品福利视频一区二区三区| 国产高清精品在线| 91精品婷婷国产综合久久竹菊| 亚洲视频综合| 91免费国产精品| 久久无码精品丰满人妻| 亚洲色图一区二区| 91精品婷婷国产综合久久蝌蚪| 亚洲一区二区三区毛片| 四虎884aa成人精品| 男女免费观看在线爽爽爽视频| 91高清视频在线观看| 一区二区在线| 99亚洲伊人久久精品影院| 中文字幕一区在线观看视频| av官网在线播放| 国产极品粉嫩福利姬萌白酱| 91在线视频免费观看| 91n.com在线观看| 蜜桃视频成人在线观看| 国产精品一区免费视频| 国产免费一级片| 在线免费观看av电影| 亚洲综合视频在线播放| 国产在线拍揄自揄拍无码| 操日韩av在线电影| 国产伦精品一区二区三区| 91看片淫黄大片一级| 欧美偷窥清纯综合图区| 国产91在线免费观看| 一区二区三区四区激情| 999久久久免费精品国产| 欧美一级电影在线| 精品伦理一区二区三区| 日韩午夜在线播放| 国产精品视频第一区二区三区| 亚洲无码精品在线观看| 国产精品高潮呻吟AV无码| 国产精品国产三级国产专播品爱网| 中文字幕av在线免费观看| 国产 日韩 欧美 综合 一区| 熟女俱乐部一区二区视频在线| 亚洲深夜福利| 国产精品久久久久久久久久久久久久久久久久| 中国黄色一级视频| 国产福利微拍精品一区二区| 亚洲综合图区| 青青草成人网| 性欧美13一14内谢| 九九99久久精品在免费线bt| 欧美日韩中文一区| av动漫在线播放| 国色天香久久精品国产一区| 韩国av网站在线| 色黄久久久久久| 青青操国产视频| 国产精品一区二区无线| 免费日韩在线观看| 久久久综合香蕉尹人综合网| 亚洲xxxx视频| 欧美日韩亚洲国产精品| 精品亚洲一区二区三区在线播放| 欧美激情亚洲自拍| 最近2019年好看中文字幕视频| 欧美日本在线视频| 在线播放性xxx欧美| 农村末发育av片一区二区| 日韩精品一区二区三区在线视频| 噼里啪啦国语在线观看免费版高清版| 91亚洲国产成人精品性色| 欧美精品一区二区三区高清aⅴ| 七七久久电影网| 国产精品天干天干在观线| 在线免费电影观看| 极品白浆推特女神在线观看| 国产精品草草| 一区二区三区免费在线观看| 亚洲mv大片欧洲mv大片| 成人在线黄色| 亚洲a一区二区三区| 欧美羞羞视频| 亚洲一级黄色录像| 高清一级毛片视频| 亚洲天堂一区在线| 日韩亚洲一区在线播放| 毛片a片免费观看| 国产精品va无码一区二区三区| 国产精品毛片一区二区在线看舒淇| 亚洲精品一区二区三区新线路| 欧美激情亚洲天堂| 51vv免费精品视频一区二区| 国产一区二区三区视频| 久久99精品国产99久久6尤物| 成人在线免费电影网站| www.欧美日韩国产在线| 免费视频爱爱太爽了| 亚洲欧洲国产日本综合| 免费人成又黄又爽又色| 国产女精品视频网站免费| 极品粉嫩小仙女高潮喷水久久| 91视频.com| 综合 欧美 亚洲日本| 国产高清自拍视频在线观看| 国产精品99久久久精品无码| 日本成人伦理电影| 米奇精品一区二区三区| 伊人久久久久久久久久久久久| 91亚洲精品丁香在线观看| 日本在线视频www鲁啊鲁| 久久波多野结衣| 人人澡人人爽人人揉| 中文字幕在线字幕中文| 亚洲综合激情在线| 久久精品超碰| 免费成人在线观看| 精品久久一区二区三区蜜桃| 久久综合婷婷综合| 亚洲国产婷婷香蕉久久久久久99| 国产精品人人做人人爽人人添| 美女毛片在线看| 人妻丰满熟妇av无码久久洗澡| 亚洲成人三级在线| 91久久夜色精品国产网站| 国产日韩欧美激情| 丁香六月色婷婷| 日本二三区不卡| 极品少妇一区二区三区精品视频| 热99精品里视频精品| 福利视频在线| 亚洲色图13p| 欧美日韩不卡一区| 国产精品视频免费一区| 性生交大片免费看女人按摩| 国产精品一区二区三区成人| 国产亚洲欧美在线精品| 一道本无吗一区| 国产乱码精品一区二区三区亚洲人| 欧美区日韩区| 国产69精品99久久久久久宅男| 欧美成人中文字幕在线| 自拍日韩亚洲一区在线| 国产美女无遮挡网站| 欧美日韩伦理片| 日韩国产小视频| 国产精品区一区二区三在线播放| 国产一区亚洲二区| 黑粗硬长欧美在线视频免费的| 国产精品二区影院| 宅男一区二区三区| 黄色国产网站在线播放| 少妇激情综合网| 成年人网站av| 色婷婷一区二区三区av免费看| 美女日韩在线中文字幕| 日韩电影在线视频| 麻豆成人入口| 欧美精品成人网| 婷婷成人av| 日韩中文字幕免费在线观看| 神马久久高清| 五月天男人天堂| 亚洲在线资源| 日韩一区二区三区国产| 免费观看在线午夜影视| 深夜国产在线播放| 成人黄色av网站在线| 国产精品美女www| 中文字幕xxxx| 偷拍盗摄高潮叫床对白清晰| 日韩在线免费高清视频| www.夜夜操| 中文字幕一区二区三区免费看| 99热精品国产| av播放在线观看| 亚洲aⅴ天堂av在线电影软件| 91九色在线porn| 夜夜未满十八勿进的爽爽影视| www 成人av com| 四虎影院一区二区| 久久精品xxx| 日日夜夜天堂| 在线观看完整版免费| 你懂的在线观看视频| 天堂网在线观看视频| youjizz.com亚洲| 日韩高清av电影| 午夜精品在线观看| av资源久久| 国产黄色精品视频| 麻豆国产在线视频| 国内自拍视频在线看免费观看| 日本一区二区不卡在线| 水莓100国产免费av在线播放| 欧美大奶一区二区| 黄页网站免费在线观看| 91九色国产在线| 99热自拍偷拍| h网站免费观看| 国产又黄又粗又猛又爽的视频| 国产视频丨精品|在线观看| 亚洲曰韩产成在线| 国产免费裸体视频| 岛国91视频| 久久香蕉国产线看观看网| 丰满人妻一区二区三区四区| 国产精品久久久久久在线观看| 日日悠悠久久| 欧美videos大乳护士334| 国产精品一级无码| 国产一区二区三区在线视频观看| 黄页在线播放| 国产成人鲁鲁免费视频a| 欧美日韩情趣电影| 色婷婷av一区二区三区软件| 欧美亚洲愉拍一区二区| 日韩欧美中文一区二区| 91精品国产综合久久久久久丝袜| www.日韩.com| 天堂av在线中文| 日本三级中文字幕在线观看| 久久91亚洲| 18涩涩午夜精品.www| 午夜免费播放观看在线视频| 九九视频免费观看视频精品| 久久av国产紧身裤| 91精品免费久久久久久久久| 午夜久久福利视频| 93久久精品日日躁夜夜躁欧美| 亚洲电影成人av99爱色| 久久最新资源网| 亚洲午夜精品视频| 亚洲欧洲色图综合| 亚洲裸色大胆大尺寸艺术写真| 无尽裸体动漫2d在线观看| 欧美性受ⅹ╳╳╳黑人a性爽| 欧美性xxxx在线播放| 国产黄色美女视频| 国产精品午夜国产小视频| 色偷偷亚洲男人天堂| 艳母动漫在线免费观看| 国产情侣一区| 伊人久久久久久久久久久久久久| 鲁丝一区二区三区| 欧美精品在线一区| 色综久久综合桃花网| 老头老太做爰xxx视频| 蜜臀va亚洲va欧美va天堂| 91精品91久久久中77777| 999在线观看精品免费不卡网站| 欧美妇女性影城| 视频区小说区图片区| 色av性av丰满av| 国产精品一区二区资源| 免费看精品久久片| 亚洲精品一区二区网址| 中文字幕av一区二区三区四区| 中文字幕综合网| 久久久久无码国产精品一区| 欧美野外性xxxxfeexxxx| 亚洲传媒在线| 亚洲wwwav| 国产日韩精品一区二区浪潮av| 国产精品一卡二卡三卡| 国产农村妇女毛片精品| 99久久精品国产麻豆演员表| 国产精品久久久久久久久久久久久久久久久久| 色猫视频免费观看| 中文字幕第六页| 黄色一级片在线看|