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

如何更好地理解中間件和洋蔥模型

開發 前端
本文阿寶哥將跟大家一起來學習 Koa 的中間件,不過這里阿寶哥不打算一開始就亮出廣為人知的 “洋蔥模型圖”,而是先來介紹一下 Koa 中的中間件是什么?

[[349804]]

 相信用過 Koa、Redux 或 Express 的小伙伴對中間件都不會陌生,特別是在學習 Koa 的過程中,還會接觸到 “洋蔥模型”。

本文阿寶哥將跟大家一起來學習 Koa 的中間件,不過這里阿寶哥不打算一開始就亮出廣為人知的 “洋蔥模型圖”,而是先來介紹一下 Koa 中的中間件是什么?

一、Koa 中間件

在 @types/koa-compose 包下的 index.d.ts 頭文件中我們找到了中間件類型的定義:

  1. // @types/koa-compose/index.d.ts 
  2. declare namespace compose { 
  3.   type Middleware<T> = (context: T, next: Koa.Next) => any
  4.   type ComposedMiddleware<T> = (context: T, next?: Koa.Next) => Promise<void>; 
  5.    
  6. // @types/koa/index.d.ts => Koa.Next 
  7. type Next = () => Promise<any>; 

通過觀察 Middleware 類型的定義,我們可以知道在 Koa 中,中間件就是普通的函數,該函數接收兩個參數:context 和 next。其中 context 表示上下文對象,而 next 表示一個調用后返回 Promise 對象的函數對象。

了解完 Koa 的中間件是什么之后,我們來介紹 Koa 中間件的核心,即 compose 函數:

  1. function wait(ms) { 
  2.   return new Promise((resolve) => setTimeout(resolve, ms || 1)); 
  3.  
  4. const arr = []; 
  5. const stack = []; 
  6.  
  7. // type Middleware<T> = (context: T, next: Koa.Next) => any
  8. stack.push(async (context, next) => { 
  9.   arr.push(1); 
  10.   await wait(1); 
  11.   await next(); 
  12.   await wait(1); 
  13.   arr.push(6); 
  14. }); 
  15.  
  16. stack.push(async (context, next) => { 
  17.   arr.push(2); 
  18.   await wait(1); 
  19.   await next(); 
  20.   await wait(1); 
  21.   arr.push(5); 
  22. }); 
  23.  
  24. stack.push(async (context, next) => { 
  25.   arr.push(3); 
  26.   await wait(1); 
  27.   await next(); 
  28.   await wait(1); 
  29.   arr.push(4); 
  30. }); 
  31.  
  32. await compose(stack)({}); 

對于以上的代碼,我們希望執行完 compose(stack)({}) 語句之后,數組 arr 的值為 [1, 2, 3, 4, 5, 6]。這里我們先不關心 compose 函數是如何實現的。我們來分析一下,如果要求數組 arr 輸出期望的結果,上述 3 個中間件的執行流程:

1.開始執行第 1 個中間件,往 arr 數組壓入 1,此時 arr 數組的值為 [1],接下去等待 1 毫秒。為了保證 arr 數組的第 1 項為 2,我們需要在調用 next 函數之后,開始執行第 2 個中間件。

2.開始執行第 2 個中間件,往 arr 數組壓入 2,此時 arr 數組的值為 [1, 2],繼續等待 1 毫秒。為了保證 arr 數組的第 2 項為 3,我們也需要在調用 next 函數之后,開始執行第 3 個中間件。

3.開始執行第 3 個中間件,往 arr 數組壓入 3,此時 arr 數組的值為 [1, 2, 3],繼續等待 1 毫秒。為了保證 arr 數組的第 3 項為 4,我們要求在調用第 3 個中間的 next 函數之后,要能夠繼續往下執行。

4.當第 3 個中間件執行完成后,此時 arr 數組的值為 [1, 2, 3, 4]。因此為了保證 arr 數組的第 4 項為 5,我們就需要在第 3 個中間件執行完成后,返回第 2 個中間件 next 函數之后語句開始執行。

5.當第 2 個中間件執行完成后,此時 arr 數組的值為 [1, 2, 3, 4, 5]。同樣,為了保證 arr 數組的第 5 項為 6,我們就需要在第 2 個中間件執行完成后,返回第 1 個中間件 next函數之后語句開始執行。

6.當第 1 個中間件執行完成后,此時 arr 數組的值為 [1, 2, 3, 4, 5, 6]。

為了更直觀地理解上述的執行流程,我們可以把每個中間件當做 1 個大任務,然后在以 next 函數為分界點,在把每個大任務拆解為 3 個 beforeNext、next 和 afterNext 3 個小任務。

 

 

 

 

在上圖中,我們從中間件一的 beforeNext 任務開始執行,然后按照紫色箭頭的執行步驟完成中間件的任務調度。在 77.9K 的 Axios 項目有哪些值得借鑒的地方 這篇文章中,阿寶哥從 任務注冊、任務編排和任務調度 3 個方面去分析 Axios 攔截器的實現。同樣,阿寶哥將從上述 3 個方面來分析 Koa 中間件機制。

1.1 任務注冊

在 Koa 中,我們創建 Koa 應用程序對象之后,就可以通過調用該對象的 use 方法來注冊中間件:

  1. const Koa = require('koa'); 
  2. const app = new Koa(); 
  3.  
  4. app.use(async (ctx, next) => { 
  5.   const start = Date.now(); 
  6.   await next(); 
  7.   const ms = Date.now() - start; 
  8.   console.log(`${ctx.method} ${ctx.url} - ${ms}ms`); 
  9. }); 

其實 use 方法的實現很簡單,在 lib/application.js 文件中,我們找到了它的定義:

  1. // lib/application.js 
  2. module.exports = class Application extends Emitter {   
  3.   constructor(options) { 
  4.     super(); 
  5.     // 省略部分代碼  
  6.     this.middleware = []; 
  7.   } 
  8.    
  9.  use(fn) { 
  10.    if (typeof fn !== 'function') throw new TypeError('middleware must be a function!'); 
  11.    // 省略部分代碼  
  12.    this.middleware.push(fn); 
  13.    return this; 
  14.   } 

由以上代碼可知,在 use 方法內部會對 fn 參數進行類型校驗,當校驗通過時,會把 fn 指向的中間件保存到 middleware 數組中,同時還會返回 this 對象,從而支持鏈式調用。

1.2 任務編排

在 77.9K 的 Axios 項目有哪些值得借鑒的地方 這篇文章中,阿寶哥參考 Axios 攔截器的設計模型,抽出以下通用的任務處理模型:

 

 

 

 

在該通用模型中,阿寶哥是通過把前置處理器和后置處理器分別放到 CoreWork 核心任務的前后來完成任務編排。而對于 Koa 的中間件機制來說,它是通過把前置處理器和后置處理器分別放到 await next() 語句的前后來完成任務編排


 

  1. // 統計請求處理時長的中間件 
  2. app.use(async (ctx, next) => { 
  3.   const start = Date.now(); 
  4.   await next(); 
  5.   const ms = Date.now() - start; 
  6.   console.log(`${ctx.method} ${ctx.url} - ${ms}ms`); 
  7. }); 

 

1.3 任務調度

通過前面的分析,我們已經知道了,使用 app.use 方法注冊的中間件會被保存到內部的 middleware 數組中。要完成任務調度,我們就需要不斷地從 middleware 數組中取出中間件來執行。中間件的調度算法被封裝到 koa-compose 包下的 compose 函數中,該函數的具體實現如下:

  1. /** 
  2.  * Compose `middleware` returning 
  3.  * a fully valid middleware comprised 
  4.  * of all those which are passed. 
  5.  * 
  6.  * @param {Array} middleware 
  7.  * @return {Function
  8.  * @api public 
  9.  */ 
  10. function compose(middleware) { 
  11.   // 省略部分代碼 
  12.   return function (context, next) { 
  13.     // last called middleware # 
  14.     let index = -1; 
  15.     return dispatch(0); 
  16.     function dispatch(i) { 
  17.       if (i <= index
  18.         return Promise.reject(new Error("next() called multiple times")); 
  19.       index = i; 
  20.       let fn = middleware[i]; 
  21.       if (i === middleware.length) fn = next
  22.       if (!fn) return Promise.resolve(); 
  23.       try { 
  24.         return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); 
  25.       } catch (err) { 
  26.         return Promise.reject(err); 
  27.       } 
  28.     } 
  29.   }; 

compose 函數接收一個參數,該參數的類型是數組,調用該函數之后會返回一個新的函數。接下來我們將以前面的例子為例,來分析一下 await compose(stack)({}); 語句的執行過程。

1.3.1 dispatch(0)

 

 

 

 

由上圖可知,當在第一個中間件內部調用 next 函數,其實就是繼續調用 dispatch 函數,此時參數 i 的值為 1。

1.3.2 dispatch(1)

 

 

 

 

由上圖可知,當在第二個中間件內部調用 next 函數,仍然是調用 dispatch 函數,此時參數 i 的值為 2。

1.3.3 dispatch(2)

 

 

 

 

由上圖可知,當在第三個中間件內部調用 next 函數,仍然是調用 dispatch 函數,此時參數 i 的值為 3。

1.3.4 dispatch(3)

 

 

 

 

由上圖可知,當 middleware 數組中的中間件都開始執行之后,如果調度時未顯式地設置 next 參數的值,則會開始返回 next 函數之后的語句繼續往下執行。當第三個中間件執行完成后,就會返回第二中間件 next 函數之后的語句繼續往下執行,直到所有中間件中定義的語句都執行完成。

分析完 compose 函數的實現代碼,我們來看一下 Koa 內部如何利用 compose 函數來處理已注冊的中間件。

  1. const Koa = require('koa'); 
  2. const app = new Koa(); 
  3.  
  4. // 響應 
  5. app.use(ctx => { 
  6.   ctx.body = '大家好,我是阿寶哥'
  7. }); 
  8.  
  9. app.listen(3000); 

利用以上的代碼,我就可以快速啟動一個服務器。其中 use 方法我們前面已經分析過了,所以接下來我們來分析 listen 方法,該方法的實現如下所示:

  1. // lib/application.js 
  2. module.exports = class Application extends Emitter {   
  3.   listen(...args) { 
  4.     debug('listen'); 
  5.     const server = http.createServer(this.callback()); 
  6.     return server.listen(...args); 
  7.   } 

很明顯在 listen 方法內部,會先通過調用 Node.js 內置 HTTP 模塊的 createServer 方法來創建服務器,然后開始監聽指定的端口,即開始等待客戶端的連接。

另外,在調用 http.createServer 方法創建 HTTP 服務器時,我們傳入的參數是 this.callback(),該方法的具體實現如下所示:

  1. // lib/application.js 
  2. const compose = require('koa-compose'); 
  3.  
  4. module.exports = class Application extends Emitter {   
  5.   callback() { 
  6.     const fn = compose(this.middleware); 
  7.     if (!this.listenerCount('error')) this.on('error', this.onerror); 
  8.  
  9.     const handleRequest = (req, res) => { 
  10.       const ctx = this.createContext(req, res); 
  11.       return this.handleRequest(ctx, fn); 
  12.     }; 
  13.     return handleRequest; 
  14.   } 

在 callback 方法內部,我們終于見到了久違的 compose 方法。當調用 callback 方法之后,會返回 handleRequest 函數對象用來處理 HTTP 請求。每當 Koa 服務器接收到一個客戶端請求時,都會調用 handleRequest 方法,在該方法會先創建新的 Context 對象,然后在執行已注冊的中間件來處理已接收的 HTTP 請求:

  1. module.exports = class Application extends Emitter {   
  2.   handleRequest(ctx, fnMiddleware) { 
  3.     const res = ctx.res; 
  4.     res.statusCode = 404; 
  5.     const onerror = err => ctx.onerror(err); 
  6.     const handleResponse = () => respond(ctx); 
  7.     onFinished(res, onerror); 
  8.     return fnMiddleware(ctx).then(handleResponse).catch(onerror); 
  9.   } 

好的,Koa 中間件的內容已經基本介紹完了,對 Koa 內核感興趣的小伙伴,可以自行研究一下。接下來我們來介紹洋蔥模型及其應用。

二、洋蔥模型2.1 洋蔥模型簡介

 

 

 

 

(圖片來源:https://eggjs.org/en/intro/egg-and-koa.html)

在上圖中,洋蔥內的每一層都表示一個獨立的中間件,用于實現不同的功能,比如異常處理、緩存處理等。每次請求都會從左側開始一層層地經過每層的中間件,當進入到最里層的中間件之后,就會從最里層的中間件開始逐層返回。因此對于每層的中間件來說,在一個 請求和響應 周期中,都有兩個時機點來添加不同的處理邏輯。

2.2 洋蔥模型應用

除了在 Koa 中應用了洋蔥模型之外,該模型還被廣泛地應用在 Github 上一些不錯的項目中,比如 koa-router 和阿里巴巴的 midway、umi-request 等項目中。

介紹完 Koa 的中間件和洋蔥模型,阿寶哥根據自己的理解,抽出以下通用的任務處理模型:

 

 

 

 

上圖中所述的中間件,一般是與業務無關的通用功能代碼,比如用于設置響應時間的中間件:

  1. // x-response-time 
  2. async function responseTime(ctx, next) { 
  3.   const start = new Date(); 
  4.   await next(); 
  5.   const ms = new Date() - start; 
  6.   ctx.set("X-Response-Time", ms + "ms"); 

其實,對于每個中間件來說,前置處理器和后置處理器都是可選的。比如以下中間件用于設置統一的響應內容:

  1. // response 
  2. async function respond(ctx, next) { 
  3.   await next(); 
  4.   if ("/" != ctx.url) return
  5.   ctx.body = "Hello World"

盡管以上介紹的兩個中間件都比較簡單,但你也可以根據自己的需求來實現復雜的邏輯。Koa 的內核很輕量,麻雀雖小五臟俱全。它通過提供了優雅的中間件機制,讓開發者可以靈活地擴展 Web 服務器的功能,這種設計思想值得我們學習與借鑒。

好的,這次就先介紹到這里,后面有機會的話,阿寶哥在單獨介紹一下 Redux 或 Express 的中間件機制。

 

責任編輯:姜華 來源: 全棧修仙之路
相關推薦

2022-10-25 08:01:17

洋蔥模型Koa

2021-06-15 10:01:02

應用系統軟件

2020-08-19 08:39:05

中間件前端設計模式

2011-05-24 15:10:48

2021-02-11 08:21:02

中間件開發CRUD

2022-07-14 08:17:59

中間件微服務開發

2011-12-30 10:31:38

云計算

2021-08-07 07:23:08

Webpack中間件模型

2022-03-18 06:32:43

遞歸Python算法

2018-07-29 12:27:30

云中間件云計算API

2018-02-01 10:19:22

中間件服務器系統

2016-11-11 21:00:46

中間件

2022-11-18 07:54:02

Go中間件項目

2014-06-05 14:41:20

金蝶中間件

2021-07-19 07:55:24

Redux中間件原理

2023-10-18 07:32:27

中間件技術HTTP請求

2021-06-29 09:34:00

洋蔥模型中間件

2009-06-16 15:55:06

JBoss企業中間件

2012-11-30 10:21:46

移動中間件

2023-06-29 10:10:06

Rocket MQ消息中間件
點贊
收藏

51CTO技術棧公眾號

欧美自拍偷拍一区二区| 双性尿奴穿贞c带憋尿| 思思99re6国产在线播放| 国产在线视频一区二区三区| 欧美美女操人视频| jlzzjizz在线播放观看| 成人一级视频| 亚洲第一在线综合网站| 日本公妇乱淫免费视频一区三区| 99热这里只有精品5| 亚洲男人影院| 欧美成人小视频| 日韩乱码人妻无码中文字幕久久| 91国产精品| 狠狠干狠狠久久| 亚洲综合网中心| 精品国产九九九| 日日摸夜夜添夜夜添精品视频| 欧美成人黑人xx视频免费观看| 国产三级视频网站| 久久久久久亚洲精品美女| 色八戒一区二区三区| 青青草综合视频| 国产精品四虎| 91网站在线观看视频| 91亚洲精品久久久久久久久久久久| 影音先锋在线国产| 激情亚洲成人| 美女撒尿一区二区三区| 国产成人午夜视频网址| 中文字幕 91| 在线播放高清视频www| 亚洲激情中文1区| 亚洲一区二区三区精品动漫| 你懂的在线播放| 成人h版在线观看| 成人淫片在线看| 伊人免费在线观看高清版| 国产精品日本| 午夜精品久久久久久久男人的天堂| 成熟的女同志hd| 天天久久综合| 日韩一区二区三区国产| 懂色av蜜桃av| 国产欧美一区| 亚洲欧美一区二区三区四区| 免费a在线观看播放| 都市激情亚洲欧美| 欧美xxx久久| 岛国大片在线免费观看| 国产精品日韩精品在线播放| 在线不卡中文字幕| 国产亚洲视频一区| 在线视频成人| 制服丝袜成人动漫| 91网址在线观看精品| 精品一区二区三区免费看| 在线成人小视频| 日本少妇xxx| 一区二区三区免费在线看| 日韩精品最新网址| 在线观看免费视频国产| 久久91在线| 国产视频亚洲视频| 免费黄色片网站| 日韩欧美伦理| 久久偷看各类女兵18女厕嘘嘘| 91高清免费观看| 国产一区欧美| 18久久久久久| 天天爱天天做天天爽| 日日夜夜精品视频天天综合网| 国产狼人综合免费视频| 国产精品久久久久久久久久久久久久久久久久 | 国产高清不卡| 欧洲一区二区三区免费视频| 亚洲欧美日韩一级| 视频精品一区| 亚洲国产日韩欧美在线图片| 三上悠亚ssⅰn939无码播放| 欧美丝袜丝交足nylons172| 自拍偷拍免费精品| 久一视频在线观看| 久久一区欧美| 国产日韩欧美在线看| www.亚洲黄色| 久久先锋影音av| 影音先锋欧美在线| 女人黄色免费在线观看| 色8久久精品久久久久久蜜| 中文字幕 91| 国产精品久久久久久久久久白浆| 亚洲午夜未删减在线观看 | 国产精品国产三级国产aⅴ9色| 亚洲性在线观看| 成人小视频免费观看| 欧美在线一区二区三区四区| 黄色免费在线网站| 欧美视频精品一区| 国产高清999| 亚洲精华一区二区三区| 精品国偷自产在线视频99| 日韩三级视频在线播放| 久久99精品网久久| 蜜桃臀一区二区三区| 国产写真视频在线观看| 懂色av中文一区二区三区天美| 久久撸在线视频| 欧美三级午夜理伦三级在线观看 | 精品视频一区二区| 欧美性天天影视| 狠狠久久五月精品中文字幕| 欧美色图校园春色| 日韩精品首页| 欧美一级在线亚洲天堂| 国产99999| 亚洲国产精品ⅴa在线观看| 国产美女永久无遮挡| 国产精品99| 亚洲精品一区在线观看香蕉| 久久婷婷一区二区| 国内精品免费**视频| 色婷婷精品国产一区二区三区| 九色91在线| 91精品国产91久久久久久最新毛片| 短视频在线观看| 一区二区自拍| 91亚洲精品丁香在线观看| 99中文字幕一区| 欧美日韩国产影院| 中文字幕99页| 欧美日韩专区| 91亚洲国产成人久久精品网站| av资源种子在线观看| 欧美天堂在线观看| 丰满大乳奶做爰ⅹxx视频| 欧美黄免费看| 亚洲资源在线看| 国产在线69| 7777精品伊人久久久大香线蕉超级流畅 | 精品国产一区二区在线| 中文字幕精品无码亚| 国产亚洲欧美日韩在线一区| 亚洲精品中文字幕无码蜜桃| 日韩最新在线| 91爱爱小视频k| 天天综合网在线观看| 亚洲风情在线资源站| 亚洲黄色小说在线观看| 黄色国产精品| 国产精品视频福利| 182在线视频观看| 亚洲精品国产美女| 成人免费看片98欧美| 久久综合五月天婷婷伊人| 女人喷潮完整视频| 精品一区免费| 国产精品久久久久久久电影 | 精品网站aaa| 97色在线观看| 精品无吗乱吗av国产爱色| 色丁香久综合在线久综合在线观看| 免费看污片的网站| 秋霞成人午夜伦在线观看| 相泽南亚洲一区二区在线播放| 日本一区免费网站| 久久久成人精品视频| 99国产精品久久久久久久成人| 一区二区高清视频在线观看| 在线播放av网址| 国产日韩欧美三级| 色999日韩自偷自拍美女| 日韩综合久久| 欧美极品少妇xxxxⅹ喷水| 午夜视频在线免费播放| 欧美性受极品xxxx喷水| 日本少妇aaa| 福利电影一区二区三区| 无码人妻丰满熟妇区毛片18| 波多野结衣在线观看一区二区| 91亚洲精品在线观看| 国产www视频在线观看| 亚洲片在线资源| 97成人在线观看| 亚洲成人一区二区| 国产熟女一区二区| 国产成人欧美日韩在线电影| 免费观看美女裸体网站| 久久蜜桃av| 国产精品美女xx| 日本美女久久| 国内精品久久影院| 91网页在线观看| 欧美成人激情免费网| 无码人妻久久一区二区三区| 亚洲欧洲综合另类在线| 香蕉网在线播放| 国产精品一品二品| 十八禁视频网站在线观看| 亚洲欧美综合久久久| 鲁丝一区二区三区免费| 成人黄色91| 国产成人精品一区二区三区| 污网站在线免费看| 在线观看成人黄色| 天天操天天操天天操| 91精品国产综合久久福利软件 | 日本h片在线| 在线电影av不卡网址| 亚洲欧美综合一区二区| 日韩视频中午一区| 中文字幕一二区| 精品国产成人在线| 免费一级黄色大片| 亚洲视频一区二区在线观看| 91黄色免费视频| 国产精品综合av一区二区国产馆| 国产成人综合一区| 亚洲一区二区三区免费在线观看| 国产免费一区二区三区四在线播放| 免费av一区二区三区四区| 俄罗斯精品一区二区三区| 成人永久在线| 国产在线观看一区二区三区| 国产综合av| 日本欧美中文字幕| а√天堂中文在线资源8| 欧美超级免费视 在线| 欧美精品电影| 日韩中文字幕第一页| 国产小视频在线播放| 亚洲欧洲美洲在线综合| 天堂av在线免费观看| 亚洲а∨天堂久久精品9966| va视频在线观看| 欧美一级一区二区| 国产欧美日韩成人| 欧美日韩国产系列| 在线视频欧美亚洲| 欧美四级电影在线观看| 国产suv精品一区二区33| 欧美色另类天堂2015| 日本韩国欧美中文字幕| 岛国av一区二区三区| 日本中文字幕在线| 91久久精品日日躁夜夜躁欧美| 超碰超碰超碰超碰| 色综合激情五月| 一级特黄免费视频| 欧美亚一区二区| 又污又黄的网站| 91精品欧美久久久久久动漫| 99热这里只有精| 欧美成人激情免费网| 少妇人妻偷人精品一区二区| 亚洲高清免费观看高清完整版| 天堂av资源在线| 亚洲美女av网站| 91最新在线| 久久这里有精品视频| 国产区美女在线| 91精品国产色综合| 日韩精品第一| 91精品免费久久久久久久久| 欧美经典一区| 国产一区二区视频在线免费观看| 欧美黄色网视频| 日本高清不卡一区二区三| 欧美丰满日韩| 黄色三级中文字幕| 天堂av在线一区| 亚洲精品20p| 国产成人精品1024| 亚洲一区二区观看| 中文字幕国产精品一区二区| 久久久久亚洲av片无码| 亚洲一区二区三区四区的| 久久免费激情视频| 欧美日韩你懂得| 亚洲产国偷v产偷v自拍涩爱| 日韩高清免费在线| 欧洲不卡视频| 91精品国产91久久久久久久久| 日本精品网站| 91亚色免费| 精品一区二区三区中文字幕老牛| 免费观看中文字幕| 国产日韩精品视频一区二区三区 | 亚洲永久精品在线观看| 欧美揉bbbbb揉bbbbb| 国产黄色av片| 揄拍成人国产精品视频| 人人澡人人添人人爽一区二区| 日本久久久久亚洲中字幕| 欧美黄色一级| 亚洲电影网站| 亚洲人成毛片在线播放女女| 欧美女同在线观看| 26uuu精品一区二区| 日韩在线一卡二卡| 欧美午夜激情在线| 国产av一区二区三区精品| 亚洲欧美成人网| 秋霞在线视频| 国产欧美精品一区二区三区-老狼 国产欧美精品一区二区三区介绍 国产欧美精品一区二区 | 国产精品巨作av| 一区二区三区四区视频在线观看 | 中日韩av在线播放| 91丝袜高跟美女视频| 青青草手机在线视频| 欧美唯美清纯偷拍| 欧美18xxxxx| 欧美精品videosex牲欧美| 日本国产亚洲| 日本一区二区在线| 日韩午夜电影| 国产清纯白嫩初高中在线观看性色| 国产精品久久久久久久久搜平片 | 欧美特级一级片| 欧美午夜精品免费| 三区在线观看| 97色在线视频| 加勒比色老久久爱综合网| 欧美日韩一级在线| 另类的小说在线视频另类成人小视频在线| 中文字幕三级电影| 亚洲国产欧美一区二区三区丁香婷| 国产精品主播一区二区| 最近2019中文字幕第三页视频| 亚洲va中文在线播放免费| 久久爱av电影| 亚洲啪啪91| 艳妇乳肉豪妇荡乳xxx| 亚洲综合丁香婷婷六月香| 国产农村老头老太视频| 日韩一区在线视频| 欧美激情啪啪| 中文字幕一区综合| 麻豆成人综合网| 欧美日韩国产一二三区| 欧美日韩日本视频| 日本三级视频在线播放| 国产欧美日韩免费看aⅴ视频| 精品视频黄色| 一级黄色录像在线观看| 中文字幕一区二区三| 91国偷自产中文字幕久久| 日日噜噜噜夜夜爽亚洲精品| 天天综合在线观看| 最新视频 - x88av| 国产成人在线视频免费播放| 精品97人妻无码中文永久在线| 精品国内片67194| 久草在线中文最新视频| 欧美不卡三区| 日本在线不卡视频| 艳妇荡乳欲伦69影片| 精品美女一区二区三区| av剧情在线观看| 欧美在线视频二区| 麻豆中文一区二区| 全网免费在线播放视频入口| 日韩欧美一级特黄在线播放| 2021天堂中文幕一二区在线观| 精品在线一区| 日本免费在线视频不卡一不卡二| 日本成人免费在线观看| 日韩欧美二区三区| 成人观看网址| 日韩一区免费观看| 国产伦精品一区二区三区免费 | 欧美精品亚洲二区| 伊人福利在线| 久久av一区二区三区漫画| 日本 国产 欧美色综合| 特一级黄色录像| 亚洲精品一区中文| 91成人精品观看| 国产精品裸体瑜伽视频| 亚洲国产成人一区二区三区| 国产日韩一级片| 51久久精品夜色国产麻豆| 欧美岛国激情| 亚洲自拍偷拍精品| 欧美体内she精视频| 黄色污污视频在线观看| 日韩久久久久久久久久久久久| 国产自产v一区二区三区c| 日韩精品人妻中文字幕| 在线播放国产精品| av不卡一区二区| 最新天堂在线视频| 欧美日韩美女在线| 黄色精品在线观看| 欧美日韩国产精品一卡| 国产精品99久| 中文字幕第三页| 97在线观看免费| 91tv精品福利国产在线观看| 天天躁日日躁aaaxxⅹ|