午夜视频免费看_日韩三级电影网站_国产精品久久一级_亚洲一级在线播放_人妻体内射精一区二区三区_91夜夜揉人人捏人人添红杏_91福利在线导航_国产又粗又猛又黄又爽无遮挡_欧美日韩一区在线播放_中文字幕一区二区三区四区不卡 _日日夜夜精品视频免费观看_欧美韩日一区二区三区

主頁 > 知識庫 > 詳解Go語言RESTful JSON API創建

詳解Go語言RESTful JSON API創建

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

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

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

JSON API是什么?

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

基本的Web服務器

從根本上講,RESTful服務首先是Web服務。 因此我們可以先看看Go語言中基本的Web服務器是如何實現的。下面例子實現了一個簡單的Web服務器,對于任何請求,服務器都響應請求的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服務器使用Go標準庫的兩個基本函數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()
}

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

> go run basic_server.go

添加路由

雖然標準庫包含有router, 但是我發現很多人對它的工作原理感覺很困惑。 我在自己的項目中使用過各種不同的第三方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))
}

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

> go get github.com/gorilla/mux

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

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

創建一些基本的路由

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

假設我們要創建一個基本的ToDo應用, 于是我們的代碼就變成下面這樣:

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設計的開始。

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

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

基本模型

路由現在已經就緒,是時候創建Model了,可以用model發送和檢索數據。在Go語言中,model可以使用結構體來實現,而其他語言中model一般都是使用類來實現。

package main

import (
  "time"
)

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

type Todos []Todo

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

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

返回一些JSON

我們有了基本的模型,那么我們可以模擬一些真實的響應了。我們可以為TodoIndex模擬一些靜態的數據列表。

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)
}

// ...

現在我們創建了一個靜態的Todos分片來響應客戶端請求。注意,如果你請求http://localhost:8080/todos, 就會得到下面的響應:

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

更好的Model

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

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

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

拆分代碼

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

我們準備創建下面的文件,然后將相應代碼移到具體的代碼文件中:

  1. main.go: 程序入口文件。
  2. handlers.go: 路由相關的處理器。
  3. routes.go: 路由。
  4. todo.go: todo相關的代碼。
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

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

輸出Web日志

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

首先我們需要有對web請求打日志的能力,就像很多流行web服務器那樣的。 在Go語言中,標準庫里邊沒有web日志包或功能, 因此我們需要自己創建。

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函數,可以給handler進行包裝修飾。

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

應用Logger修飾器

要應用Logger修飾符, 我們可以創建router, 我們只需要簡單的將我們所有的當前路由都包到其中, NewRouter函數修改如下:

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
}

現在再次運行我們的程序,我們就可以看到日志大概如下:

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

這個路由文件太瘋狂...讓我們重構它吧

路由routes文件現在已經變得稍微大了些, 下面我們將它分解成多個文件:

  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
}

另外再承擔一些責任

到目前為止,我們已經有了一些相當好的樣板代碼(boilerplate), 是時候重新審視我們的處理器了。我們需要稍微多的責任。 首先修改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)
  }
}

這里發生了兩件事。 首先,我們設置了響應類型并告訴客戶端期望接受JSON。第二,我們明確的設置了響應狀態碼。

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

稍等片刻,我們的數據庫在哪里?

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

我們創建一個repo.go文件,內容如下:

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

我們創建了模擬數據庫,我們使用并賦予id, 因此我們相應的也需要更新我們的Todo結構體。

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

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

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, 現在是時候進入存儲一些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。這樣是保護服務器免受惡意攻擊的好方法。假設如果有人想要給你服務器發送500GB的JSON怎么辦?

我們讀取body以后,我們解構Todo結構體。 如果失敗,我們作出正確的響應,使用恰當的響應碼422, 但是我們依然使用json響應回去。 這樣可以允許客戶端理解有錯發生了, 而且有辦法知道到底發生了什么錯誤。

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

POST一些JSON

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

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

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

[
  {
    "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"
  }
]

我們還沒有做的事情

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

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

eTag - 如果你正在構建一些需要擴展的東西,你可能需要實現eTag。

還有什么?

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

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

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

總結

對我來說,最重要的,需要記住的是我們要建立一個負責任的API。 發送適當的狀態碼,header等,這些是API廣泛采用的關鍵。我希望本文能讓你盡快開始自己的API。

參考鏈接

Go語言RESTful JSON API實現
JSON API
Gorilla Web Toolkit
httprouter
JSON Web Tokens
eTag

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

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

標簽:瀘州 阿壩 晉中 泰安 東營 滄州 駐馬店 昭通

巨人網絡通訊聲明:本文標題《詳解Go語言RESTful JSON API創建》,本文關鍵詞  詳解,語言,RESTful,JSON,API,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《詳解Go語言RESTful JSON API創建》相關的同類信息!
  • 本頁收集關于詳解Go語言RESTful JSON API創建的相關信息資訊供網民參考!
  • 推薦文章
    国产夫绿帽单男3p精品视频| 日韩精品免费在线视频| 久久久国产成人精品| 久久一区免费| 污污内射在线观看一区二区少妇 | a级片免费观看| 亚洲另类在线观看| 成人综合在线观看| 在线视频国内一区二区| 欧美激情一区二区三区成人 | 屁屁影院国产第一页| 国产三级精品在线不卡| 免费av不卡在线| 国产偷拍一区二区| 亚洲精品自拍动漫在线| 久久精品国产电影| 好色先生视频污| 国产精品精品软件男同| 国产尤物一区二区| 欧美一级一级性生活免费录像| 国产在线拍偷自揄拍精品| 日韩高清第一页| 超碰福利在线观看| 色综合一个色综合亚洲| 国产精品一区二区三| 国产精品一级无码| 日韩高清不卡一区二区三区| 欧美日产在线观看| 翡翠波斯猫1977年美国| av中文字幕免费观看| 国产麻豆精品视频| 亚洲色图综合网| 老汉色影院首页| 视频一区亚洲 | 欧美性xxxx69| 欧美黑人猛猛猛| 91视频com| 久久精品视频在线| 国产女大学生av| 91片黄在线观看喷潮| 亚洲日本一区二区三区| 青青久久aⅴ北条麻妃| mm131亚洲精品| 亚洲av片一区二区三区| 日韩欧美激情四射| 亚洲午夜在线观看| 日韩人妻精品中文字幕| 亚洲午夜一二三区视频| 92国产精品久久久久首页 | 神马影院午夜我不卡影院| 国产精品99精品无码视| 亚洲欧美激情在线| 日本欧美国产在线| 右手影院亚洲欧美| 久久国产免费看| 亚洲人成电影网站色xx| 国产69精品久久久久999小说| 国产又粗又猛又黄又爽无遮挡| 欧洲一区在线观看| 日韩福利一区二区三区| 四虎成人在线观看| 欧美午夜视频网站| 视频一区不卡| 97视频免费在线| 欧美成人r级一区二区三区| 欧美日韩亚洲国产成人| 亚洲精品无码久久久久| 欧美午夜电影一区| 亚洲一区二区三区欧美| 国产女人爽到高潮a毛片| 日韩一区二区电影| 这里只有精品66| 亚洲av无码国产综合专区| 欧美tk丨vk视频| 黄色一级视频在线播放| 香蕉视频黄在线观看| 亚洲欧洲国产精品| 中文字幕12页| 26uuu色噜噜精品一区二区| 国产精品一区二区三区免费视频| 日韩亚洲欧美中文字幕| 精品久久中文字幕| 手机看片日韩国产| 日韩和的一区二区| 欧美激情一二三| 网站永久看片免费| 色综合天天做天天爱| a级网站在线观看| 久久在线精品| 97激碰免费视频| 中文字幕五月天| 欧美日韩亚洲网| 午夜精品短视频| 色婷婷综合视频| 久久99精品久久久久久噜噜 | 亚洲精品久久久久久久久| 中文字幕第38页| 久久青草欧美一区二区三区| 国产福利一区二区三区在线观看| 中文字幕第2页| 一区二区av在线| 日韩 中文字幕| 欧美性xxxx极品高清hd直播| 免费不卡av在线| 国产三区在线视频| www夜片内射视频日韩精品成人| 日韩视频免费观看| 欧美性x x x| 精品黑人一区二区三区久久| 中文在线字幕观看| 欧美午夜激情视频| 亚洲精品一二三四五区| 国产欧美精品区一区二区三区| 久久伊人一区二区| 日韩av不卡在线观看| 成人自拍性视频| 好吊色在线观看| 欧洲美女免费图片一区| 看黄色一级大片| 久久高清视频免费| 日韩精品一区二区亚洲av| 日韩中文字幕在线视频播放| 四虎免费在线视频| 久久午夜电影网| 成人免费视频网站| 日韩极品在线观看| 97超级碰碰| 日本不卡123| 国产精品免费一区二区三区观看| 丝袜美腿亚洲一区| 懂色中文一区二区三区在线视频| 天天操天天操天天操| 国产精品自产拍在线观| 亚洲第一色视频| 成人高清视频观看www| 亚洲第一色视频| 国产又爽又黄的激情精品视频| 国产 日韩 欧美 综合| 国产精品一区二区久久国产| 五月婷婷激情在线| 91入口在线观看| 久久99蜜桃精品| 亚洲人一区二区| 久久精品一区二区三区不卡 | 91在线观看地址| 日韩av电影免费观看高清| 91精品国产综合久久久蜜臀九色| 国色天香2019中文字幕在线观看| 在线播放精品视频| 国产欧美在线视频| 国内精品在线播放| 亚洲高清123| 国产99一区视频免费| 亚洲区一区二区三区| 国产精品久久久久久久久晋中| 国产男女在线观看| 欧美中文字幕久久| 一级片久久久久| 久久亚洲精品成人| 亚洲av无码片一区二区三区| 国产这里只有精品| 国产一区二区在线观看免费| 成人av在线播放观看| 婷婷综合五月天| 北岛玲一区二区| 伊人青青综合网站| 国产sm主人调教女m视频| 国产日本一区二区三区| 久久蜜桃一区二区| 亚洲精品乱码久久久久久动漫| 7777精品伊人久久久大香线蕉完整版 | 91女厕偷拍女厕偷拍高清| 日本成人黄色网| 精品欧美一区二区久久| 欧美日韩综合一区二区三区| 国产精品高潮呻吟久久av野狼| 麻豆国产尤物av尤物在线观看| 在线观看欧美视频| 亚洲av色香蕉一区二区三区| 裸模一区二区三区免费| 亚洲精品欧美激情| 色欲av无码一区二区三区| 欧美日本黄视频| 激情综合五月天| 成人免费观看视频在线观看| 精品国产91亚洲一区二区三区婷婷| 无码人妻av一区二区三区波多野 | 国产黑丝在线一区二区三区| 88av.com| 一区二区三区视频免费| 少妇高潮一区二区三区69| 欧美a级免费视频| 日韩一级高清毛片| 国产精品欧美综合亚洲| 亚洲在线色站| 欧美色爱综合网| 亚洲久久在线观看| 久久国产手机看片| 午夜电影网一区| 久久香蕉精品视频| 国产九色精品| 欧美日韩在线一区| 波多野结衣视频网站| 欧美一区二区福利| 欧美三级电影网站| 一二三四区在线| 日韩一二区视频| 亚洲精品久久久久久久久久久久久 | 女人被狂躁c到高潮| 午夜精品一区二区三区在线视 | www插插插无码视频网站| 国产丝袜视频一区| 蜜桃视频一区二区三区在线观看| www.日本xxxx| 久久久午夜视频| 欧美国产精品一区| 久久爱一区二区| 国产视频在线观看一区| 欧美天天综合网| 国产一区二区自拍视频| 黄色激情在线视频| 久久精品91久久香蕉加勒比| 99久久伊人久久99| 欧美性生交大片| 欧美第一黄网| 日韩三级高清在线| 日韩国产欧美视频| 亚洲 欧美 日韩在线| 91夜夜未满十八勿入爽爽影院| 亚洲午夜激情网站| 91成年人视频| 亚洲第一狼人区| 国产极品jizzhd欧美| 日韩欧美精品在线观看| 欧美一级做性受免费大片免费| 亚洲欧美日韩三级| 国产精品一区二区久久久久| 91福利社在线观看| 免费人成在线不卡| 久久国产劲爆∧v内射| 国产精品一区二区不卡视频| 日韩精品一区二区三区蜜臀| 久久99精品久久久久久动态图 | 欧美高清一区二区| 亚洲小视频在线| 亚洲三级视频在线观看| 国产v在线观看| aaaaaav| 伊人久久大香线蕉午夜av| 久久精品视频中文字幕| 亚洲国产一区在线观看| 天堂在线观看av| 熟女少妇一区二区三区| 欧美下载看逼逼| 欧美巨乳在线观看| 日韩欧美精品网站| 国产成人亚洲综合a∨猫咪| 动漫精品一区一码二码三码四码| 黄色一级在线视频| 成人激情在线播放| 亚洲美女av网站| 亚洲欧美偷拍另类a∨色屁股| 一级视频在线播放| 日本一区二区三区网站| 国产卡一卡二在线| 国产成人精彩在线视频九色| 日韩欧美综合在线| 国产欧美精品一区二区色综合 | 一区二区三区蜜桃| 视频在线观看一区| 日韩高清免费av| 97精品人人妻人人| 中日韩在线视频| 国产精品免费电影| 亚洲美女福利视频网站| 图片区小说区区亚洲影院| 成人激情午夜影院| 一区二区三区www污污污网站| 中文字幕一区二区三区人妻| 国产情侣第一页| 亚洲精品免费网站| 北条麻妃久久精品| 欧美日韩在线亚洲一区蜜芽| 国产视频911| 美女免费视频一区二区| 无码人妻aⅴ一区二区三区有奶水| 手机av免费看| 亚洲最大综合网| 在线观看日韩片| 亚洲综合精品伊人久久| 欧美激情免费在线| 亚洲精品xxxx| 欧美亚洲动漫制服丝袜| 欧美国产一区在线| 国产乱理伦片在线观看夜一区| 国产精品无码AV| www.av视频在线观看| 免费看污片网站| 亚洲精品第三页| 可以看毛片的网址| 五月婷婷一区| 91久久极品少妇xxxxⅹ软件| 国外成人在线播放| 亚洲一二在线观看| 日韩视频国产视频| 在线观看国产精品网站| 亚洲精品成人少妇| 国产视频一区二区在线| 国产成a人无v码亚洲福利| 玖玖精品视频| 成 人 免费 黄 色| 正在播放亚洲精品| 日韩av在线播| 欧美成人一二三区| 日韩人妻无码一区二区三区| 搡的我好爽在线观看免费视频| 日韩精品xxxx| 青春草国产视频| 青青在线免费视频| 在线码字幕一区| 亚洲精品在线视频观看| 欧美日韩综合另类| 美女亚洲精品| 久久av免费观看| 99爱精品视频| 91在线播放视频| 18成人免费观看网站下载| 91久久久在线| 亚洲综合在线小说| 99re视频| 国产精品一级久久久| 国产欧美日韩综合精品二区| 成人午夜影院在线观看| 国产精品污www一区二区三区| 国产经品一区二区| 国产精品日韩一区二区 | 99国产在线视频| 成人动漫在线视频| 精品网站在线看| 欧美一区二区三区四区在线观看地址| 欧美xxxx黑人又粗又长精品| 日韩高清国产精品| 国产精品h视频| 青草视频在线观看视频| 缅甸午夜性猛交xxxx| 99视频在线免费| av在线免费观看不卡| 国产精品无码专区| 欧美福利在线视频| 国产第一页在线播放| 波多野结衣高清视频| 国产高清免费av| 视频一区二区国产| 久久国产精品72免费观看| 高清国产午夜精品久久久久久| 久久午夜老司机| 亚洲精品国产第一综合99久久| 日本福利一区二区| 欧美sm极限捆绑bd| 最近2019中文免费高清视频观看www99 | 日韩黄色三级视频| 国产精品一区二区人人爽| 久久综合五月| 99re热视频精品| 综合电影一区二区三区 | 国产精品亚洲人在线观看| 久久精品视频免费观看| 黄色精品一区二区| 精品国产乱码久久久久久久久 | 精品免费视频123区| 91亚洲精品国产| 一级全黄裸体片| 美女福利视频在线观看| 中文字幕在线观看免费| 美女视频一区免费观看| 久久综合九色综合97婷婷| 欧美日韩亚洲精品内裤| 日韩av资源在线播放| 欧美孕妇与黑人孕交| 九色一区二区| 手机看片福利盒子久久| 亚洲天堂av中文字幕| 国产一区二区网站| 国产成人在线看| 日韩欧美国产一区二区| 一区二区三区视频观看| 国产日韩欧美日韩大片| 欧美福利精品| 九九久久九九久久| 波多野结衣三级视频| 国产网友自拍视频| 亚洲aⅴ在线观看| 国产精品日韩成人| 欧美成人性战久久| 欧美一区在线直播| 一本一本a久久| 丰满人妻一区二区三区免费视频棣| 国产精品suv一区二区69| 日韩高清国产一区在线| 一区二区国产视频| 国产亚洲欧洲高清一区| 成人情视频高清免费观看电影| 99久久激情视频| 久久精品视频国产| 精品亚洲aⅴ乱码一区二区三区| 五月婷婷欧美视频| 欧美国产第一页| 手机看片日韩国产| 欧美色视频一区二区三区在线观看| 五月天久久久久久|