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

實戰:用取消參數使 Go net/http 服務更靈活

開發 前端
超時既難以捉摸,卻又真實地存在于我們生活的由網絡連接的世界中。在我寫這篇文章的同時,隔壁兩個同事正在用他們的智能手機打字,也許是在跟與他們相距萬里的人聊天。網絡使這一切變為可能。

關于超時,可以把開發者分為兩類:一類是了解超時多么難以捉摸的人,另一類是正在感受超時如何難以捉摸的人。

超時既難以捉摸,卻又真實地存在于我們生活的由網絡連接的世界中。在我寫這篇文章的同時,隔壁兩個同事正在用他們的智能手機打字,也許是在跟與他們相距萬里的人聊天。網絡使這一切變為可能。

[[349023]]

這里要說的是網絡及其復雜性,作為寫網絡服務的我們,必須掌握如何高效地駕馭它們,并規避它們的缺陷。

閑話少說,來看看超時和它們是如何影響我們的 net/http 服務的。

服務超時 — 基本原理

web 編程中,超時通常分為客戶端和服務端超時兩種。我之所以要研究這個主題,是因為我自己遇到了一個有意思的服務端超時的問題。這也是本文我們將要重點討論服務側超時的原因。

先解釋下基本術語:超時是一個時間間隔(或邊界),用來標識在這個時間段內要完成特定的行為。如果在給定的時間范圍內沒有完成操作,就產生了超時,這個操作會被取消。

從一個 net/http 的服務的初始化中,能看出一些超時的基礎配置:

 

  1. srv := &http.Server{ 
  2.     ReadTimeout:       1 * time.Second
  3.     WriteTimeout:      1 * time.Second
  4.     IdleTimeout:       30 * time.Second
  5.     ReadHeaderTimeout: 2 * time.Second
  6.     TLSConfig:         tlsConfig, 
  7.     Handler:           srvMux, 

http.Server 類型的服務可以用四個不同的 timeout 來初始化:

  • ReadTimeout:讀取包括請求體的整個請求的最大時長
  • WriteTimeout:寫響應允許的最大時長
  • IdleTimetout:當開啟了保持活動狀態(keep-alive)時允許的最大空閑時間
  • ReadHeaderTimeout:允許讀請求頭的最大時長

對上述超時的圖表展示:

 

實戰:用取消參數使 Go net/http 服務更靈活

服務生命周期和超時

當心!不要以為這些就是你所需要的所有的超時了。除此之外還有很多超時,這些超時提供了更小的粒度控制,對于我們的持續運行的 HTTP 處理器不會生效。

請聽我解釋。

timeout 和 deadline

如果我們查看 net/http 的源碼,尤其是看到 `conn` 類型[1] 時,我們會發現conn 實際上使用了 net.Conn 連接,net.Conn 表示底層的網絡連接:

  1. // Taken from: https://github.com/golang/go/blob/bbbc658/src/net/http/server.go#L247 
  2. // A conn represents the server-side of an HTTP connection
  3. type conn struct { 
  4.     // server is the server on which the connection arrived. 
  5.     // Immutable; never nil. 
  6.     server *Server 
  7.  
  8.     // * Snipped * 
  9.  
  10.     // rwc is the underlying network connection
  11.     // This is never wrapped by other types and is the value given out 
  12.     // to CloseNotifier callers. It is usually of type *net.TCPConn or 
  13.     // *tls.Conn. 
  14.     rwc net.Conn 
  15.  
  16.     // * Snipped * 

換句話說,我們的 HTTP 請求實際上是基于 TCP 連接的。從類型上看,TLS 連接是 *net.TCPConn 或 *tls.Conn 。

serve 函數[2]處理每一個請求[3]時調用 readRequest 函數。readRequest使用我們設置的 timeout 值[4]來設置 TCP 連接的 deadline:

 

  1. // Taken from: https://github.com/golang/go/blob/bbbc658/src/net/http/server.go#L936 
  2. // Read next request from connection
  3. func (c *conn) readRequest(ctx context.Context) (w *response, err error) { 
  4.         // *Snipped* 
  5.  
  6.         t0 := time.Now() 
  7.         if d := c.server.readHeaderTimeout(); d != 0 { 
  8.                 hdrDeadline = t0.Add(d) 
  9.         } 
  10.         if d := c.server.ReadTimeout; d != 0 { 
  11.                 wholeReqDeadline = t0.Add(d) 
  12.         } 
  13.         c.rwc.SetReadDeadline(hdrDeadline) 
  14.         if d := c.server.WriteTimeout; d != 0 { 
  15.                 defer func() { 
  16.                         c.rwc.SetWriteDeadline(time.Now().Add(d)) 
  17.                 }() 
  18.         } 
  19.  
  20.         // *Snipped* 

從上面的摘要中,我們可以知道:我們對服務設置的 timeout 值最終表現為 TCP 連接的 deadline 而不是 HTTP 超時。

所以,deadline 是什么?工作機制是什么?如果我們的請求耗時過長,它們會取消我們的連接嗎?

一種簡單地理解 deadline 的思路是,把它理解為對作用于連接上的特定的行為的發生限制的一個時間點。例如,如果我們設置了一個寫的 deadline,當過了這個 deadline 后,所有對這個連接的寫操作都會被拒絕。

盡管我們可以使用 deadline 來模擬超時操作,但我們還是不能控制處理器完成操作所需的耗時。deadline 作用于連接,因此我們的服務僅在處理器嘗試訪問連接的屬性(如對 http.ResponseWriter 進行寫操作)之后才會返回(錯誤)結果。

為了實際驗證上面的論述,我們來創建一個小的 handler,這個 handler 完成操作所需的耗時相對于我們為服務設置的超時更長:

 

  1. package main 
  2.  
  3. import ( 
  4.  "fmt" 
  5.  "io" 
  6.  "net/http" 
  7.  "time" 
  8.  
  9. func slowHandler(w http.ResponseWriter, req *http.Request) { 
  10.  time.Sleep(2 * time.Second
  11.  io.WriteString(w, "I am slow!\n"
  12.  
  13. func main() { 
  14.  srv := http.Server{ 
  15.   Addr:         ":8888"
  16.   WriteTimeout: 1 * time.Second
  17.   Handler:      http.HandlerFunc(slowHandler), 
  18.  } 
  19.  
  20.  if err := srv.ListenAndServe(); err != nil { 
  21.   fmt.Printf("Server failed: %s\n", err) 
  22.  } 

上面的服務有一個 handler,這個 handler 完成操作需要兩秒。另一方面,http.Server 的 WriteTimeout 屬性設為 1 秒。基于服務的這些配置,我們猜測 handler 不能把響應寫到連接。

我們可以用 go run server.go 來啟動服務。使用 curl localhost:8888 來發送一個請求:

 

  1. time curl localhost:8888 
  2. curl: (52) Empty reply from server 
  3. curl localhost:8888  0.01s user 0.01s system 0% CPU 2.021 total 

這個請求需要兩秒來完成處理,服務返回的響應是空的。雖然我們的服務知道在 1 秒之后我們寫不了響應了,但 handler 還是多耗了 100% 的時間(2 秒)來完成處理。

雖然這是個類似超時的處理,但它更大的作用是在到達超時時間時,阻止服務進行更多的操作,結束請求。在我們上面的例子中,handler 在完成之前一直在處理請求,即使已經超出響應寫超時時間(1 秒)100%(耗時 2 秒)。

最根本的問題是,對于處理器來說,我們應該怎么設置超時時間才更有效?

處理超時

我們的目標是確保我們的 slowHandler 在 1s 內完成處理。如果超過了 1s,我們的服務會停止運行并返回對應的超時錯誤。

在 Go 和一些其它編程語言中,組合往往是設計和開發中最好的方式。標準庫的 `net/http` 包[5]有很多相互兼容的元素,開發者可以不需經過復雜的設計考慮就可以輕易將它們組合在一起。

基于此,net/http 包提供了`TimeoutHandler`[6] — 返回了一個在給定的時間限制內運行的 handler。

函數簽名:

  1. func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler 

第一個參數是 Handler,第二個參數是 time.Duration (超時時間),第三個參數是 string 類型,當到達超時時間后返回的信息。

用 TimeoutHandler 來封裝我們的 slowHandler,我們只需要:

 

  1. package main 
  2.  
  3. import ( 
  4.  "fmt" 
  5.  "io" 
  6.  "net/http" 
  7.  "time" 
  8.  
  9. func slowHandler(w http.ResponseWriter, req *http.Request) { 
  10.  time.Sleep(2 * time.Second
  11.  io.WriteString(w, "I am slow!\n"
  12.  
  13. func main() { 
  14.  srv := http.Server{ 
  15.   Addr:         ":8888"
  16.   WriteTimeout: 5 * time.Second
  17.   Handler:      http.TimeoutHandler(http.HandlerFunc(slowHandler), 1*time.Second"Timeout!\n"), 
  18.  } 
  19.  
  20.  if err := srv.ListenAndServe(); err != nil { 
  21.   fmt.Printf("Server failed: %s\n", err) 
  22.  } 

兩個需要留意的地方是:

  • 我們在 http.TimetoutHandler 里封裝 slowHanlder,超時時間設為 1s,超時信息為 “Timeout!”。
  • 我們把 WriteTimeout 增加到 5s,以給予 http.TimeoutHandler 足夠的時間執行。如果我們不這么做,當 TimeoutHandler 開始執行時,已經過了 deadline,不能再寫到響應。

如果我們再啟動服務,當程序運行到 slow handler 時,會有如下輸出:

 

  1. time curl localhost:8888 
  2. Timeout! 
  3. curl localhost:8888  0.01s user 0.01s system 1% CPU 1.023 total 

1s 后,我們的 TimeoutHandler 開始執行,阻止運行 slowHandler,返回文本信息 ”Timeout!“。如果我們設置信息為空,handler 會返回默認的超時響應信息,如下:

  1. <html> 
  2.   <head> 
  3.     <title>Timeout</title> 
  4.   </head> 
  5.   <body> 
  6.    <h1>Timeout</h1> 
  7.   </body> 
  8. </html> 

如果忽略掉輸出,這還算是整潔,不是嗎?現在我們的程序不會有過長耗時的處理;也避免了有人惡意發送導致長耗時處理的請求時,導致的潛在的 DoS 攻擊。

盡管我們設置超時時間是一個偉大的開始,但它仍然只是初級的保護。如果你可能會面臨 DoS 攻擊,你應該采用更高級的保護工具和技術。(可以試試Cloudflare[7] )

我們的 slowHandler 僅僅是個簡單的 demo。但是,如果我們的程序復雜些,能向其他服務和資源發出請求會發生什么呢?如果我們的程序在超時時向諸如 S3 的服務發出了請求會怎么樣?

會發生什么?

未處理的超時和請求取消

我們稍微展開下我們的例子:

 

  1. func slowAPICall() string { 
  2.  d := rand.Intn(5) 
  3.  select { 
  4.  case <-time.After(time.Duration(d) * time.Second): 
  5.   log.Printf("Slow API call done after %s seconds.\n", d) 
  6.   return "foobar" 
  7.  } 
  8.  
  9. func slowHandler(w http.ResponseWriter, r *http.Request) { 
  10.  result := slowAPICall() 
  11.  io.WriteString(w, result+"\n"

我們假設最初我們不知道 slowHandler 由于通過 slowAPICall 函數向 API 發請求導致需要耗費這么長時間才能處理完成,

slowAPICall 函數很簡單:使用 select 和一個能阻塞 0 到 5 秒的 time.After 。當經過了阻塞的時間后,time.After 方法通過它的 channel 發送一個值,返回 "foobar" 。

(另一種方法是,使用 sleep(time.Duration(rand.Intn(5)) * time.Second),但我們仍然使用 select,因為它會使我們下面的例子更簡單。)

如果我們運行起服務,我們預期超時 handler 會在 1 秒之后中斷請求處理。來發送一個請求驗證一下:

 

  1. time curl localhost:8888 
  2. Timeout! 
  3. curl localhost:8888  0.01s user 0.01s system 1% CPU 1.021 total 

通過觀察服務的輸出,我們會發現,它是在幾秒之后打出日志的,而不是在超時 handler 生效時打出:

 

  1. $ Go run server.go 
  2. 2019/12/29 17:20:03 Slow API call done after 4 seconds. 

這個現象表明:雖然 1 秒之后請求超時了,但是服務仍然完整地處理了請求。這就是在 4 秒之后才打出日志的原因。

雖然在這個例子里問題很簡單,但是類似的現象在生產中可能變成一個嚴重的問題。例如,當 slowAPICall 函數開啟了幾個百個協程,每個協程都處理一些數據時。或者當它向不同系統發出多個不同的 API 發出請求時。這種耗時長的的進程,它們的請求方/客戶端并不會使用服務端的返回結果,會耗盡你系統的資源。

所以,我們怎么保護系統,使之不會出現類似的未優化的超時或取消請求呢?

上下文超時和取消

Go 有一個包名為 `context`[8] 專門處理類似的場景。

context 包在 Go 1.7 版本中提升為標準庫,在之前的版本中,以`golang.org/x/net/context`[9] 的路徑作為 Go Sub-repository Packages[10]出現。

這個包定義了 Context 類型。它最初的目的是保存不同 API 和不同處理的截止時間、取消信號和其他請求相關的值。如果你想了解關于 context 包的其他信息,可以閱讀 Golang's blog[11] 中的 “Go 并發模式:Context”(譯注:Go Concurrency Patterns: Context) .

net/http 包中的的 Request 類型已經有 context 與之綁定。從 Go 1.7 開始,Request 新增了一個返回請求的上下文的 `Context` 方法[12]。對于進來的請求,在客戶端關閉連接、請求被取消(HTTP/2 中)或 ServeHTTP 方法返回后,服務端會取消上下文。

我們期望的現象是,當客戶端取消請求(輸入了 CTRL + C)或一段時間后TimeoutHandler 繼續執行然后終止請求時,服務端會停止后續的處理。進而關閉所有的連接,釋放所有被運行中的處理進程(及它的所有子協程)占用的資源。

我們把 Context 作為參數傳給 slowAPICall 函數:

 

  1. func slowAPICall(ctx context.Context) string { 
  2.  d := rand.Intn(5) 
  3.  select { 
  4.  case <-time.After(time.Duration(d) * time.Second): 
  5.   log.Printf("Slow API call done after %d seconds.\n", d) 
  6.   return "foobar" 
  7.  } 
  8.  
  9. func slowHandler(w http.ResponseWriter, r *http.Request) { 
  10.  result := slowAPICall(r.Context()) 
  11.  io.WriteString(w, result+"\n"

在例子中我們利用了請求上下文,實際中怎么用呢?`Context` 類型[13]有個 Done 屬性,類型為 <-chan struct{}。當進程處理完成時,Done 關閉,此時表示上下文應該被取消,而這正是例子中我們需要的。

我們在 slowAPICall 函數中用 select 處理 ctx.Done 通道。當我們通過 Done 通道接收一個空的 struct 時,意味著上下文取消,我們需要讓 slowAPICall 函數返回一個空字符串。

 

  1. func slowAPICall(ctx context.Context) string { 
  2.  d := rand.Intn(5) 
  3.  select { 
  4.  case <-ctx.Done(): 
  5.   log.Printf("slowAPICall was supposed to take %s seconds, but was canceled.", d) 
  6.   return "" 
  7.         //time.After() 可能會導致內存泄漏 
  8.  case <-time.After(time.Duration(d) * time.Second): 
  9.   log.Printf("Slow API call done after %d seconds.\n", d) 
  10.   return "foobar" 
  11.  } 

(這就是使用 select 而不是 time.Sleep -- 這里我們只能用 select 處理 Done 通道。)

在這個簡單的例子中,我們成功得到了結果 -- 當我們從 Done 通道接收值時,我們打印了一行日志到 STDOUT 并返回了一個空字符串。在更復雜的情況下,如發送真實的 API 請求,你可能需要關閉連接或清理文件描述符。

我們再啟動服務,發送一個 cRUL 請求:

 

  1. # The cURL command: 
  2. $ curl localhost:8888 
  3. Timeout! 
  4.  
  5. # The server output
  6. $ Go run server.go 
  7. 2019/12/30 00:07:15 slowAPICall was supposed to take 2 seconds, but was canceled. 

檢查輸出:我們發送了 cRUL 請求到服務,它耗時超過 1 秒,服務取消了 slowAPICall 函數。我們幾乎不需要寫任何代碼。TimeoutHandler 為我們代勞了 -- 當處理耗時超過預期時,TimeoutHandler 終止了處理進程并取消請求上下文。

TimeoutHandler 是在 `timeoutHandler.ServeHTTP` 方法[14] 中取消上下文的:

 

  1. // Taken from: https://github.com/golang/go/blob/bbbc658/src/net/http/server.go#L3217-L3263 
  2. func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { 
  3.         ctx := h.testContext 
  4.         if ctx == nil { 
  5.          var cancelCtx context.CancelFunc 
  6.          ctx, cancelCtx = context.WithTimeout(r.Context(), h.dt) 
  7.          defer cancelCtx() 
  8.         } 
  9.         r = r.WithContext(ctx) 
  10.  
  11.         // *Snipped* 

上面例子中,我們通過調用 context.WithTimeout 來使用請求上下文。超時值 h.dt (TimeoutHandler 的第二個參數)設置給了上下文。返回的上下文是請求上下文設置了超時值后的一份拷貝。隨后,它作為請求上下文傳給r.WithContext(ctx)。

context.WithTimeout 方法執行了上下文取消。它返回了 Context 設置了一個超時值之后的副本。當到達超時時間后,就取消上下文。

這里是執行的代碼:

 

  1. // Taken from: https://github.com/golang/go/blob/bbbc6589/src/context/context.go#L486-L498 
  2. func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 
  3.  return WithDeadline(parent, time.Now().Add(timeout)) 
  4.  
  5. // Taken from: https://github.com/golang/go/blob/bbbc6589/src/context/context.go#L418-L450 
  6. func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { 
  7.         // *Snipped* 
  8.  
  9.         c := &timerCtx{ 
  10.          cancelCtx: newCancelCtx(parent), 
  11.          deadline:  d, 
  12.         } 
  13.  
  14.         // *Snipped* 
  15.  
  16.         if c.err == nil { 
  17.          c.timer = time.AfterFunc(dur, func() { 
  18.           c.cancel(true, DeadlineExceeded) 
  19.          }) 
  20.         } 
  21.         return c, func() { c.cancel(true, Canceled) } 

這里我們又看到了截止時間。WithDeadline 函數設置了一個 d 到達之后執行的函數。當到達截止時間后,它調用 cancel 方法處理上下文,此方法會關閉上下文的 done 通道并設置上下文的 timer 屬性為 nil。

Done 通道的關閉有效地取消了上下文,使我們的 slowAPICall 函數終止了它的執行。這就是 TimeoutHandler 終止耗時長的處理進程的原理。

(如果你想閱讀上面提到的源碼,你可以去看 `cancelCtx` 類型[15] 和`timerCtx` 類型[16])

有彈性的 net/http 服務

連接截止時間提供了低級的細粒度控制。雖然它們的名字中含有“超時”,但它們并沒有表現出人們通常期望的“超時”。實際上它們非常強大,但是使用它們有一定的門檻。

另一個角度講,當處理 HTTP 時,我們仍然應該考慮使用 TimeoutHandler。Go 的作者們也選擇使用它,它有多種處理,提供了如此有彈性的處理以至于我們甚至可以對每一個處理使用不同的超時。TimeoutHandler 可以根據我們期望的表現來控制執行進程。

除此之外,TimeoutHandler 完美兼容 context 包。context 包很簡單,包含了取消信號和請求相關的數據,我們可以使用這些數據來使我們的應用更好地處理錯綜復雜的網絡問題。

結束之前,有三個建議。寫 HTTP 服務時,怎么設計超時:

  • 最常用的,到達 TimeoutHandler 時,怎么處理。它進行我們通常期望的超時處理。
  • 不要忘記上下文取消。context 包使用起來很簡單,并且可以節省你服務器上的很多處理資源。尤其是在處理異常或網絡狀況不好時。
  • 一定要用截止時間。確保做了完整的測試,驗證了能提供你期望的所有功能。

 

責任編輯:未麗燕 來源: 今日頭條
相關推薦

2009-05-18 09:12:00

ASON自動交換光網絡

2015-05-04 14:12:43

2023-06-06 19:24:06

KubernetesSpark

2024-11-21 15:48:40

2011-02-23 09:48:00

Python.NET

2011-02-22 10:00:38

.NETc#IronPython

2009-06-03 09:08:20

ScalaJava類型

2017-07-18 06:08:41

2023-11-27 08:21:49

Camera2API,

2012-01-13 10:31:25

ibmdw

2020-09-14 09:33:02

網絡

2025-02-18 00:10:00

2017-02-14 15:37:32

KappaLambda

2024-01-08 08:36:29

HTTPGo代理服務器

2023-12-05 10:25:24

Python類型注解

2015-10-10 10:01:39

VMware數據中心

2012-03-13 10:40:58

Google Go

2013-12-12 10:55:21

2013-11-11 16:20:01

戴爾
點贊
收藏

51CTO技術棧公眾號

黄色电影免费在线看| 成人黄色一区二区| 800av免费在线观看| 欧美aaa级| 久久亚洲春色中文字幕久久久| 日韩中文在线视频| 18禁免费观看网站| www黄色网址| 久久成人综合| 日本精品视频一区二区三区| 国产嫩草一区二区三区在线观看| 欧美自拍偷拍网| 欧美电影免费观看| 91在线丨porny丨国产| 欧美大片欧美激情性色a∨久久| 色悠悠久久综合网| 欧美日韩在线精品一区二区三区激情综| 91不卡在线观看| 欧美久久婷婷综合色| 日本不卡一区| caoporn国产| 日韩欧美美女在线观看| 亚洲国产精品精华液网站| 国产日本欧美一区| 欧美 日韩 成人| 欧美一区国产| 久久久99久久| 国产精品成人一区二区| 欧美做受xxxxxⅹ性视频| 中文字幕资源网在线观看免费| 成人爱爱电影网址| 国外视频精品毛片| 国产精品果冻传媒| 超清av在线| av电影天堂一区二区在线 | 欧美一级电影久久| 人妻av一区二区| 123区在线| 91原创在线视频| 欧美最猛黑人xxxx黑人猛叫黄| 一本加勒比波多野结衣| 黄色在线观看www| 91麻豆免费看| 国产精品福利观看| 任我爽在线视频| 精品麻豆剧传媒av国产九九九| 伊人色综合久久天天| 成人资源av| 中文字幕69页| 999精品视频| 欧美成人一区二区三区片免费| 免费看欧美黑人毛片| 天天摸天天干天天操| 久久亚洲国产精品一区二区| 在线观看久久久久久| 污污动漫在线观看| 污的网站在线观看| 91色porny蝌蚪| 国产精品一区电影| 美女毛片在线观看| 蜜桃视频欧美| 欧美一区二区三区在线观看视频| 国产96在线 | 亚洲| 国产精品久久一区二区三区不卡| 久久国产精品第一页| 欧美疯狂性受xxxxx另类| 美女被到爽高潮视频| 国产精品99久久免费| 精品久久久一区二区| 一区不卡字幕| 六月婷婷中文字幕| 日本va欧美va精品| 国内精品久久久久久中文字幕| 亚洲精品成人无码| 国产午夜久久av| 色综合欧美在线视频区| 日本女人高潮视频| 九九在线视频| 国产91在线|亚洲| 国产成人亚洲综合| 久久久精品视频在线| 亚欧日韩另类中文欧美| 欧美一区二区女人| 密臀av一区二区三区| 青青草原av在线| 中文字幕第一页久久| 国产精品一区二区你懂得| 亚洲天堂狠狠干| 国产精品腿扒开做爽爽爽挤奶网站| www.亚洲一区| 能免费看av的网站| 国产伦精品一区二区三区免费优势| 欧美午夜影院一区| 免费无码不卡视频在线观看| 顶级网黄在线播放| 中文字幕高清不卡| 欧美一区二区福利| 欧美另类老女人| 在线国产伦理一区| 牛牛影视精品影视| 成人黄色av电影| 91麻豆桃色免费看| 亚洲天堂av在线免费观看| 亚洲免费av片| 潘金莲一级淫片aaaaaaa| 欧美精品高清| 欧美日韩裸体免费视频| 大陆极品少妇内射aaaaaa| 大乳在线免费观看| xnxx国产精品| 精品一卡二卡三卡四卡日本乱码 | 日韩av成人在线观看| 精品亚洲永久免费| 午夜av一区| 中文字幕免费精品一区高清| 成人免费无遮挡无码黄漫视频| 成人偷拍自拍| 精品国产污污免费网站入口| 久久久久久国产精品日本| 外国成人毛片| caoporn免费在线视频| 91tv精品福利国产在线观看| 中文字幕久久久| 成人免费无遮挡无码黄漫视频| 台湾佬综合网| 日韩久久午夜影院| 成人免费无码大片a毛片| 国产精品乱战久久久| 亚洲国产精品国自产拍av秋霞| 久久精品无码专区| 久久婷婷国产| 日韩精品中文字幕在线| 日本黄色片在线播放| 欧美色图婷婷| 精品在线欧美视频| 久操视频免费看| 精品一区二区三区中文字幕老牛| 国产亚洲精品久久久久久牛牛| 亚洲av成人无码久久精品| 欧美日韩高清| 久久精品精品电影网| 黄色一级片在线免费观看| 黄色综合网站| 久久久久免费视频| 国产原创视频在线| 美国av一区二区| 亚洲一区二区三区香蕉| 黄色a在线观看| 久久综合色之久久综合| 午夜免费电影一区在线观看| 麻豆av在线免费看| 亚洲成a人v欧美综合天堂| 欧美亚洲一二三区| 欧美极品在线| 精品免费日韩av| 欧美日韩高清丝袜| 中文字幕日韩欧美精品高清在线| 欧美激情亚洲另类| 国产在线观看第一页| 寂寞少妇一区二区三区| 97久久超碰国产精品电影| 国产精品人成电影| 精品人妻无码一区二区色欲产成人| 成年人网站91| 亚洲精品在线视频观看| 精精国产xxxx视频在线中文版| 黑人与娇小精品av专区| 日韩欧美亚洲另类| 欧美日韩大片免费观看| 自拍偷拍亚洲在线| 国产精品免费av一区二区| 老**午夜毛片一区二区三区| 亚洲综合视频1区| 九色在线观看视频| 亚洲国产va精品久久久不卡综合| 三级视频中文字幕| 欧美日韩一本| 欧美成人亚洲成人| 国产精品无码粉嫩小泬| 成人h版在线观看| 中文字幕中文字幕99| 电影网一区二区| 精品黑人一区二区三区久久| 国产aaaaaaaaa| 男女精品网站| 国产精品日韩二区| 国产美女福利在线| 欧美中文一区二区三区| 影音先锋黄色资源| 欧美日本一区| 91久久精品美女| wwwxxx在线观看| 岛国av午夜精品| 午夜不卡久久精品无码免费| 亚洲国产精品久久久天堂| 国产精品扒开腿爽爽爽视频| 性感美女福利视频| 亚洲午夜电影在线| 中文字幕无码毛片免费看| 99久久精品国产亚洲精品| 热久久这里只有精品| 三级视频在线看| 亚洲国产精品一区二区久久| 日韩av福利在线观看| 国产精品成人一区二区不卡| 国产精品欧美日韩久久| 国产免费av高清在线| 欧美视频中文在线看| 国产精品无码专区| 亚洲黑丝一区二区| 国产98在线|日韩| 蜜桃传媒在线观看免费进入| 日韩一级完整毛片| 丁香花五月激情| 国产一区二区三区四区五区美女| 一区不卡视频| 国产精品久一| 欧美成年人网站| 精品人妻一区二区三区蜜桃| 亚洲另类色综合网站| 日本人dh亚洲人ⅹxx| 国产精品www.| 国产精品午夜av在线| aa视频在线观看| 日韩精品中文字幕久久臀| 久草手机在线视频| 国产欧美精品在线观看| 亚洲国产日韩欧美在线观看| 99久久99久久精品国产片桃花 | 久久免费精彩视频| 国产成a人无v码亚洲福利| 国产精品日韩三级| 日韩欧美ww| 国产精品第七影院| 成人在线影视| 精品福利一二区| 日本道在线观看| 久久久久久亚洲综合影院红桃| 欧美少妇性生活视频| 日韩理论在线| 91九色露脸| 电影在线观看一区| 亚洲最新视频在线| 国产又大又黑又粗| 亚洲一二三区视频在线观看| 精品人妻一区二区三区视频| 日本va欧美va精品| 国产美女作爱全过程免费视频| 精品国产导航| 成人精品视频一区二区三区| 欧美日韩国产999| 高清乱码毛片入口| 欧美视频在线免费看| 日本不卡一区视频| 国产91精品精华液一区二区三区| 国产精品网站免费| 日韩欧美大片| 国产一区二区在线观看免费播放| 在线免费av资源| 日韩在线不卡视频| 少妇精品高潮欲妇又嫩中文字幕| 日本福利一区二区| 国模无码国产精品视频| 97se亚洲国产综合在线| 亚洲欧美自偷自拍另类| 最新亚洲激情| 一区二区三区国产福利| 国产精品nxnn| 国产女人精品视频| 18aaaa精品欧美大片h| 最近2019免费中文字幕视频三| 亚洲国产精品国自产拍久久| 91国偷自产一区二区开放时间| 中文字幕av播放| 久久精品免视看| 亚洲精品鲁一鲁一区二区三区| 久久先锋影音| 无码粉嫩虎白一线天在线观看 | 日韩精品资源| 成人在线超碰| 成人国产在线激情| 美女18一级毛片一品久道久久综合| 久久久精品视频在线观看| 欧美午夜黄色| 亚洲第一黄色网| 国产视频在线观看免费 | 免费在线激情视频| 午夜精品av| 亚洲视频在线二区| 亚洲动漫在线观看| 北条麻妃高清一区| 日韩欧美三区| 国产精品久久久久久久久久小说| 成年男女免费视频网站不卡| 美日韩精品免费观看视频| av中文天堂在线| 亚洲区在线播放| 人妻少妇一区二区三区| 日韩一区二区三区免费看| 亚洲一级视频在线观看| 色欧美乱欧美15图片| 欧美精品亚洲精品日韩精品| 一区二区三区四区在线免费观看 | 亚洲免费视频成人| 三级黄色免费观看| 国产精品网站在线播放| x88av在线| 久久久久88色偷偷免费| 香蕉视频黄色在线观看| 成人国产精品免费| 亚洲午夜久久久久久久久| 国产成人免费网站| 丰满人妻一区二区三区53视频| 精品一区二区三区免费视频| 亚洲欧美视频二区| 蜜臀91精品一区二区三区| 国产日韩成人内射视频 | |精品福利一区二区三区| 亚洲图片第一页| 国产精品―色哟哟| 一级片黄色录像| 国产精品福利av| 波多野结衣在线网址| 一区二区视频免费在线观看| 欧美日韩免费一区二区| 亚洲一区中文日韩| 蜜桃av.com| 97电影在线| 欧美jizz19性欧美| 日韩一区二区不卡| 国产男男gay体育生网站| 欧美精品18+| 国产模特av私拍大尺度 | 国产一级精品毛片| 欧美日韩国产首页在线观看| 91福利免费视频| 欧美tk—视频vk| 丝袜视频国产在线播放| 亚洲人成电影网站| 免费大片黄在线观看视频网站| 久久综合色88| av在线网页| 国产精品 欧美在线| 亚洲tv在线| 国产高清自拍一区| 亚洲欧美校园春色| 一本一生久久a久久精品综合蜜 | 能在线观看的av| 曰本一区二区三区视频| 色综合影院在线观看| 一区二区日韩欧美| 欧美黑人经典片免费观看 | 国产精品入口免费软件| 日韩三级小视频| 91蜜桃婷婷狠狠久久综合9色| 国产黄色三级网站| 卡一精品卡二卡三网站乱码| av一区二区在线看| 首页亚洲中字| 五月天男人天堂| 国产欧美一区二区三区国产幕精品| 妓院一钑片免看黄大片| 国产高清不卡二三区| 亚洲最大成人网站| 有码一区二区三区| 免费无码国产精品| 精品女同一区二区| 日本中文字幕电影在线免费观看| 久久久午夜视频| 成人国产精品| 麻豆精品蜜桃一区二区三区| 欧美99久久| 亚欧美在线观看| 99久久99久久精品国产片果冻| 日本一道本视频| 亚洲成a人v欧美综合天堂| 国产精品毛片一区二区在线看舒淇| 日韩电影大全免费观看2023年上| 黄色网在线免费看| 国产精国产精品| 全国精品免费看| 欧美黄网在线观看| 紧缚奴在线一区二区三区| 成人国产精品久久久网站| 亚洲成人激情综合网| 99精品视频在线播放免费| 在线亚洲国产精品网| 永久免费毛片在线播放| 动漫一区二区在线| 在线精品国产| 日本美女视频一区| 中文字幕+乱码+中文字幕一区| 久久久精品福利| 亚洲第一精品夜夜躁人人爽| 91三级在线| 91牛牛免费视频| 久久精品久久久| 亚洲污视频在线观看| 国产欧美日韩久久| 亚洲另类欧美日韩|