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

PostMessage 還能這樣玩

網(wǎng)絡(luò) 通信技術(shù)
本文阿寶哥以 Postmate 這個庫為例,介紹了如何基于 postMessage 來實現(xiàn)父頁面和 iframe 子頁面之間優(yōu)雅的消息通信。

 在日常工作中,消息通信是一個很常見的場景。比如大家熟悉 B/S 結(jié)構(gòu),在該結(jié)構(gòu)下,瀏覽器與服務(wù)器之間是基于 HTTP 協(xié)議進行消息通信:


然而除了 HTTP 協(xié)議之外,在一些對數(shù)據(jù)實時性要求較高的場景下,我們會使用 WebSocket 協(xié)議來完成消息通信:


對于這兩種場景,相信大家都不會陌生。接下來,阿寶哥將介紹消息通信的另外一種場景,即父頁面與 iframe 加載的子頁面之間,如何進行消息通信。

為什么會突然寫這個話題呢?其實是因為在近期項目中,阿寶哥需要實現(xiàn)父頁面與 iframe 加載的子頁面之間的消息通信。另外,剛好近期阿寶哥在寫 源碼分析 專題,所以就到 Github 上搜索 🔍 了一番,然后找到了一個不錯的項目 —— Postmate。

在閱讀完 Postmate 源碼之后,阿寶哥覺得該項目的一些設(shè)計思想挺值得借鑒的,所以就寫了這篇文章來跟大家分享一下。閱讀完本文之后,你將學(xué)到以下知識:

  • 消息系統(tǒng)中握手的作用及如何實現(xiàn)握手;
  • 消息模型的設(shè)計及如何實現(xiàn)消息驗證來保證通信安全;
  • postMessage 的使用及如何利用它實現(xiàn)父子頁面的消息通信;
  • 消息通信 API 的設(shè)計與實現(xiàn)。

好的,廢話不多說,我們先來簡單介紹一下 Postmate。

一、Postmate 簡介

[[352432]]

Postmate 是一個強大,簡單,基于 Promise 的 postMessage 庫。它允許父頁面以最小的成本與跨域的子 iframe 進行通信。該庫擁有以下特性:

  • 基于 Promise 的 API,可實現(xiàn)優(yōu)雅而簡單的通信;
  • 使用 消息驗證 來保護雙向 父 <-> 子 消息通信的安全;
  • 子對象公開父對象可以訪問的可檢索的模型對象;
  • 子對象可派發(fā)父對象已監(jiān)聽的事件;
  • 父對象可以調(diào)用子對象中的函數(shù);
  • 零依賴。如果需要可以為 Promise API 提供自定義 polyfill 或抽象;
  • 輕量,大小約 1.6 KB(minified & gzipped)。

接下來阿寶哥將從如何進行握手、如何實現(xiàn)雙向消息通信和如何斷開連接,這三個方面來分析一下 Postmate 這個庫。另外,在此期間還會穿插介紹 Postmate 項目中一些好的設(shè)計思路。

二、如何進行握手

TCP 建立連接的時候,需要進行三次握手。同樣,當父頁面與子頁面通信的時候,Postmate 也是通過 “握手” 來確保雙方能正常通信。因為 Postmate 通信的基礎(chǔ)是基于 postMessage,所以在介紹如何握手之前,我們先來簡單了解一下 postMessage API。

2.1 postMessage 簡介

對于兩個不同頁面的腳本,只有當執(zhí)行它們的頁面位于具有相同的協(xié)議、端口號以及主機時,這兩個腳本才能相互通信。window.postMessage() 方法提供了一種受控機制來規(guī)避此限制,只要正確的使用,這種方法就很安全。

2.1.1 postMessage() 語法

  1. otherWindow.postMessage(message, targetOrigin, [transfer]); 
  • otherWindow:其他窗口的一個引用,比如 iframe 的 contentWindow 屬性、執(zhí)行 window.open 返回的窗口對象等。
  • message:將要發(fā)送到其他 window 的數(shù)據(jù),它將會被結(jié)構(gòu)化克隆算法序列化。
  • targetOrigin:通過窗口的 origin 屬性來指定哪些窗口能接收到消息事件,其值可以是字符串 "*"(表示無限制)或者一個 URI。
  • transfer(可選):是一串和 message 同時傳遞的 Transferable 對象。這些對象的所有權(quán)將被轉(zhuǎn)移給消息的接收方,而發(fā)送一方將不再保有所有權(quán)。

發(fā)送方通過 postMessage API 來發(fā)送消息,而接收方可以通過監(jiān)聽 message 事件,來添加消息處理回調(diào)函數(shù),具體使用方式如下:

  1. window.addEventListener("message", receiveMessage, false); 
  2.  
  3. function receiveMessage(event) { 
  4.   let origin = event.origin || event.originalEvent.origin;  
  5.   if (origin !== "http://semlinker.com"return

2.2 Postmate 握手的實現(xiàn)

在電信和微處理器系統(tǒng)中,術(shù)語握手(Handshake,亦稱為交握)具有以下含義:

  • 在數(shù)據(jù)通信中,由硬件或軟件管理的事件序列,在進行信息交換之前,需要對操作模式的狀態(tài)互相達成協(xié)定。
  • 在接收站和發(fā)送站之間建立通信參數(shù)的過程。

對于通信系統(tǒng)來說,握手是在通信電路建立之后,信息傳輸開始之前。握手用于達成參數(shù),如信息傳輸率,字母表,奇偶校驗, 中斷過程,和其他協(xié)議特性。

而對于 Postmate 這個庫來說,握手是為了確保父頁面與 iframe 子頁面之間可以正常的通信,對應(yīng)的握手流程如下所示:

 在 Postmate 中,握手消息是由父頁面發(fā)起的,在父頁面中要發(fā)起握手信息,首先需要創(chuàng)建 Postmate 對象:

  1. const postmate = new Postmate({ 
  2.   container: document.getElementById('some-div'), // iframe的容器 
  3.   url: 'http://child.com/page.html', // 包含postmate.js的iframe子頁面地址 
  4.   name'my-iframe-name' // 用于設(shè)置iframe元素的name屬性 
  5. }); 

在以上代碼中,我們通過調(diào)用 Postmate 構(gòu)造函數(shù)來創(chuàng)建 postmate 對象,在 Postmate 構(gòu)造函數(shù)內(nèi)部含有兩個主要步驟:設(shè)置 Postmate 對象的內(nèi)部屬性和發(fā)送握手消息: 


以上流程圖對應(yīng)的代碼相對比較簡單,這里阿寶哥就不貼詳細的代碼了。感興趣的小伙伴可以閱讀 src/postmate.js 文件中的相關(guān)內(nèi)容。為了能夠響應(yīng)父頁面的握手信息,我們需要在子頁面中創(chuàng)建一個 Model 對象:

  1. const model = new Postmate.Model({ 
  2.   // Expose your model to the Parent. Property values may be functions, promises, or regular values 
  3.   height: () => document.height || document.body.offsetHeight 
  4. }); 

其中 Postmate.Model 構(gòu)造函數(shù)的定義如下:

  1. // src/postmate.js 
  2. Postmate.Model = class Model { 
  3.   constructor(model) { 
  4.     this.child = window; 
  5.     this.model = model; 
  6.     this.parent = this.child.parent; 
  7.     return this.sendHandshakeReply(); 
  8.   } 

在 Model 構(gòu)造函數(shù)中,我們可以很清楚地看到調(diào)用 sendHandshakeReply 這個方法,這里我們只看核心的代碼:

 

現(xiàn)在我們來總結(jié)一下父頁面和子頁面之間的握手流程:當子頁面加載完成后,父頁面會通過 postMessage API 向子頁面發(fā)送 handshake 握手消息。在子頁面接收到 handshake握手消息之后,同樣也會使用 postMessage API 往父頁面回復(fù) handshake-reply 消息。

另外,需要注意的是,為了保證子頁面能收到 handshake 握手消息,在 sendHandshake方法內(nèi)部會啟動一個定時器來執(zhí)行發(fā)送操作:

  1. // src/postmate.js 
  2. class Postmate { 
  3.   sendHandshake(url) { 
  4.     return new Postmate.Promise((resolve, reject) => { 
  5.       const loaded = () => { 
  6.         doSend(); 
  7.         responseInterval = setInterval(doSend, 500); 
  8.       }; 
  9.  
  10.       if (this.frame.attachEvent) { 
  11.         this.frame.attachEvent("onload", loaded); 
  12.       } else { 
  13.         this.frame.addEventListener("load", loaded); 
  14.       } 
  15.        
  16.       this.frame.src = url; 
  17.     }); 
  18.   } 

當然為了避免發(fā)送過多無效的握手信息,在 doSend 方法內(nèi)部會限制最大的握手次數(shù):

  1. const doSend = () => { 
  2.   attempt++; 
  3.   this.child.postMessage( 
  4.     { 
  5.       postmate: "handshake"
  6.       type: messageType, 
  7.       model: this.model, 
  8.     }, 
  9.     childOrigin 
  10.   ); 
  11.   // const maxHandshakeRequests = 5; 
  12.   if (attempt === maxHandshakeRequests) { 
  13.      clearInterval(responseInterval); 
  14.   } 
  15. }; 

在主應(yīng)用和子應(yīng)用雙方完成握手之后,就可以進行雙向消息通信了,下面我們來了解一下如何實現(xiàn)雙向消息通信。

三、如何實現(xiàn)雙向消息通信

在調(diào)用 Postmate 和 Postmate.Model 構(gòu)造函數(shù)之后,會返回一個 Promise 對象。而當 Promise 對象的狀態(tài)從 pending 變?yōu)?resolved 之后,就會分別返回 ParentAPI 和 ChildAPI 對象:

Postmate

  1. // src/postmate.js 
  2. class Postmate { 
  3.   constructor({ 
  4.     container = typeof container !== "undefined" ? container : document.body, 
  5.     model, url, name, classListArray = [], 
  6.   }) { 
  7.     // 省略設(shè)置 Postmate 對象的內(nèi)部屬性 
  8.     return this.sendHandshake(url); 
  9.   } 
  10.    
  11.   sendHandshake(url) { 
  12.     // 省略部分代碼 
  13.     return new Postmate.Promise((resolve, reject) => { 
  14.       const reply = (e) => { 
  15.         if (!sanitize(e, childOrigin)) return false
  16.         if (e.data.postmate === "handshake-reply") { 
  17.           return resolve(new ParentAPI(this)); 
  18.         } 
  19.         return reject("Failed handshake"); 
  20.       }; 
  21.     }); 
  22.   } 

ParentAPI

  1. class ParentAPI{ 
  2.   +get(property: any) // 獲取子頁面中Model對象上的property屬性上的值 
  3.   +call(property: any, data: any) // 調(diào)用子頁面中Model對象上的方法 
  4.   +on(eventName: any, callback: any) // 監(jiān)聽子頁面派發(fā)的事件 
  5.   +destroy() // 移除事件監(jiān)聽并刪除iframe 

Postmate.Model

  1. // src/postmate.js 
  2. Postmate.Model = class Model { 
  3.   constructor(model) { 
  4.     this.child = window; 
  5.     this.model = model; 
  6.     this.parent = this.child.parent; 
  7.     return this.sendHandshakeReply(); 
  8.   } 
  9.  
  10.   sendHandshakeReply() { 
  11.     // 省略部分代碼 
  12.     return new Postmate.Promise((resolve, reject) => { 
  13.       const shake = (e) => { 
  14.         if (e.data.postmate === "handshake") { 
  15.           this.child.removeEventListener("message", shake, false); 
  16.           return resolve(new ChildAPI(this)); 
  17.         } 
  18.         return reject("Handshake Reply Failed"); 
  19.       }; 
  20.       this.child.addEventListener("message", shake, false); 
  21.     }); 
  22.   } 
  23. }; 

ChildAPI

  1. class ChildAPI{ 
  2.   +emit(nameany, data: any

3.1 子頁面 -> 父頁面

3.1.1 子頁面發(fā)送消息

  1. const model = new Postmate.Model({ 
  2.   // Expose your model to the Parent. Property values may be functions, promises, or regular values 
  3.   height: () => document.height || document.body.offsetHeight 
  4. }); 
  5.  
  6. model.then(childAPI => { 
  7.   childAPI.emit('some-event''Hello, World!'); 
  8. }); 

在以上代碼中,子頁面可以通過 ChildAPI 對象提供的 emit 方法來發(fā)送消息,該方法的定義如下:

  1. export class ChildAPI { 
  2.   emit(name, data) { 
  3.     this.parent.postMessage( 
  4.       { 
  5.         postmate: "emit"
  6.         type: messageType, 
  7.         value: { 
  8.           name
  9.           data, 
  10.         }, 
  11.       }, 
  12.       this.parentOrigin 
  13.     ); 
  14.   } 

3.1.2 父頁面監(jiān)聽消息

  1. const postmate = new Postmate({ 
  2.   container: document.getElementById('some-div'), // iframe的容器 
  3.   url: 'http://child.com/page.html', // 包含postmate.js的iframe子頁面地址 
  4.   name'my-iframe-name' // 用于設(shè)置iframe元素的name屬性 
  5. }); 
  6.  
  7. postmate.then(parentAPI => { 
  8.   parentAPI.on('some-event', data => console.log(data)); // Logs "Hello, World!" 
  9. }); 

在以上代碼中,父頁面可以通過 ParentAPI 對象提供的 on 方法來注冊事件處理器,該方法的定義如下:

  1. export class ParentAPI { 
  2.   constructor(info) { 
  3.     this.parent = info.parent; 
  4.     this.frame = info.frame; 
  5.     this.child = info.child; 
  6.  
  7.     this.events = {}; 
  8.  
  9.     this.listener = (e) => { 
  10.       if (!sanitize(e, this.childOrigin)) return false
  11.    // 省略部分代碼 
  12.       if (e.data.postmate === "emit") { 
  13.         if (name in this.events) { 
  14.           this.events[name].forEach((callback) => { 
  15.             callback.call(this, data); 
  16.           }); 
  17.         } 
  18.       } 
  19.     }; 
  20.  
  21.     this.parent.addEventListener("message", this.listener, false); 
  22.   } 
  23.  
  24.   on(eventName, callback) { 
  25.     if (!this.events[eventName]) { 
  26.       this.events[eventName] = []; 
  27.     } 
  28.     this.events[eventName].push(callback); 
  29.   } 

3.2 消息驗證

為了保證通信的安全,在消息處理時,Postmate 會對消息進行驗證,對應(yīng)的驗證邏輯被封裝到 sanitize 方法中:

  1. const sanitize = (message, allowedOrigin) => { 
  2.   if (typeof allowedOrigin === "string" && message.origin !== allowedOrigin) 
  3.     return false
  4.   if (!message.data) return false
  5.   if (typeof message.data === "object" && !("postmate" in message.data)) 
  6.     return false
  7.   if (message.data.type !== messageType) return false
  8.   if (!messageTypes[message.data.postmate]) return false
  9.   return true
  10. }; 

對應(yīng)的驗證規(guī)則如下:

  • 驗證消息的來源是否合法;
  • 驗證是否含有消息體;
  • 驗證消息體中是否含有 postmate 屬性;
  • 驗證消息的類型是否為 "application/x-postmate-v1+json";
  • 驗證消息體中的 postmate 對應(yīng)的消息類型是否合法;

以下是 Postmate 支持的消息類型:

  1. const messageTypes = { 
  2.   handshake: 1,  
  3.   "handshake-reply": 1,  
  4.   call: 1, 
  5.   emit: 1,  
  6.   reply: 1,  
  7.   request: 1, 
  8. }; 

其實要實現(xiàn)消息驗證的提前,我們還需要定義標準的消息體模型:

  1.    postmate: "emit", // 必填:"request" | "call" 等等 
  2.    type: messageType, // 必填:"application/x-postmate-v1+json" 
  3.    // 自定義屬性 

了解完子頁面如何與父頁面進行通信及如何進行消息驗證之后,下面我們來看一下父頁面如何與子頁面進行消息通信。

3.3 父頁面 -> 子頁面

3.3.1 調(diào)用子頁面模型對象上的方法


在頁面中,通過 ParentAPI 對象提供的 call 方法,我們就可以調(diào)用子頁面模型對象上的方法:

  1. export class ParentAPI { 
  2.  call(property, data) { 
  3.     this.child.postMessage( 
  4.       { 
  5.         postmate: "call"
  6.         type: messageType, 
  7.         property, 
  8.         data, 
  9.       }, 
  10.       this.childOrigin 
  11.     ); 
  12.   } 

在 ChildAPI 對象中,會對 call 消息類型進行對應(yīng)的處理,相應(yīng)的處理邏輯如下所示:

  1. export class ChildAPI { 
  2.   constructor(info) { 
  3.   // 省略部分代碼 
  4.     this.child.addEventListener("message", (e) => { 
  5.       if (!sanitize(e, this.parentOrigin)) return
  6.       const { property, uid, data } = e.data; 
  7.        
  8.       // 響應(yīng)父頁面發(fā)送的call消息類型,用于調(diào)用Model對象上的對應(yīng)方法 
  9.       if (e.data.postmate === "call") { 
  10.         if ( 
  11.           property in this.model && 
  12.           typeof this.model[property] === "function" 
  13.         ) { 
  14.           this.model[property](data); 
  15.         } 
  16.         return
  17.       } 
  18.     }); 
  19.   } 

通過以上代碼我們可知,call 消息只能用來調(diào)用子頁面 Model 對象上的方法并不能獲取方法調(diào)用的返回值。然而在一些場景下,我們是需要獲取方法調(diào)用的返回值,接下來我們來看一下 ParentAPI 是如何實現(xiàn)這個功能。

3.3.2 調(diào)用子頁面模型對象上的方法并獲取返回值

 若需要獲取調(diào)用后的返回值,我們需要調(diào)用 ParentAPI 對象上提供的 get 方法:

  1. export class ParentAPI { 
  2.  get(property) { 
  3.     return new Postmate.Promise((resolve) => { 
  4.       // 從響應(yīng)中獲取數(shù)據(jù)并移除監(jiān)聽 
  5.       const uid = generateNewMessageId(); 
  6.       const transact = (e) => { 
  7.         if (e.data.uid === uid && e.data.postmate === "reply") { 
  8.           this.parent.removeEventListener("message", transact, false); 
  9.           resolve(e.data.value); 
  10.         } 
  11.       }; 
  12.        
  13.       // 監(jiān)聽來自子頁面的響應(yīng)消息 
  14.       this.parent.addEventListener("message", transact, false); 
  15.  
  16.       // 向子頁面發(fā)送請求 
  17.       this.child.postMessage( 
  18.         { 
  19.           postmate: "request"
  20.           type: messageType, 
  21.           property, 
  22.           uid, 
  23.         }, 
  24.         this.childOrigin 
  25.       ); 
  26.     }); 
  27.   } 

對于父頁面發(fā)送的 request 消息,在子頁面中會通過 resolveValue 方法來獲取返回結(jié)果,然后通過 postMessage 來返回結(jié)果:

  1. // src/postmate.js 
  2. export class ChildAPI { 
  3.   constructor(info) { 
  4.     this.child.addEventListener("message", (e) => { 
  5.       if (!sanitize(e, this.parentOrigin)) return
  6.       const { property, uid, data } = e.data; 
  7.        
  8.       // 響應(yīng)父頁面發(fā)送的request消息 
  9.       resolveValue(this.model, property).then((value) => 
  10.         e.source.postMessage( 
  11.           { 
  12.             property, 
  13.             postmate: "reply"
  14.             type: messageType, 
  15.             uid, 
  16.             value, 
  17.           }, 
  18.           e.origin 
  19.         ) 
  20.       ); 
  21.     }); 
  22.   } 

以上代碼中的 resolveValue 方法實現(xiàn)也很簡單:

  1. const resolveValue = (model, property) => { 
  2.   const unwrappedContext = 
  3.     typeof model[property] === "function" ? model[property]() : model[property]; 
  4.   return Postmate.Promise.resolve(unwrappedContext); 
  5. }; 

此時,我們已經(jīng)介紹了 Postmate 如何進行握手及如何實現(xiàn)雙向消息通信,最后我們來介紹一下如何斷開連接。

四、如何斷開連接

當父頁面與子頁面完成消息通信之后,我們需要斷開連接。這時我們可以調(diào)用 ParentAPI對象上的 destroy 方法來斷開連接。

  1. // src/postmate.js 
  2. export class ParentAPI { 
  3.  destroy() { 
  4.     window.removeEventListener("message", this.listener, false); 
  5.     this.frame.parentNode.removeChild(this.frame); 
  6.   } 

本文阿寶哥以 Postmate 這個庫為例,介紹了如何基于 postMessage 來實現(xiàn)父頁面和 iframe 子頁面之間優(yōu)雅的消息通信。如果你還意猶未盡的話,可以閱讀阿寶哥之前寫的與通信相關(guān)的文章:如何優(yōu)雅的實現(xiàn)消息通信? 和 你不知道的 WebSocket。

五、參考資源

  • MDN - postMessage
  • Github - postmate【編輯推薦】

 

責任編輯:姜華 來源: 全棧修仙之路
相關(guān)推薦

2021-09-05 07:55:37

前端Emoji 表情

2021-07-28 06:10:47

拖拽設(shè)計器 transmat

2024-08-02 08:38:20

Controller接口地址

2024-12-03 09:45:34

2018-12-12 11:30:54

JavaString字符串

2021-04-09 08:23:30

Css前端加載動畫

2024-01-30 09:21:29

CSS文字效果文字裝飾

2023-02-26 00:00:02

字符串分割String

2020-05-22 10:00:08

數(shù)據(jù)庫數(shù)據(jù)庫設(shè)計軟件設(shè)計

2021-01-30 07:51:59

微信微信8.0騰訊

2023-01-30 08:46:20

GoGo1兼容性

2022-10-31 08:47:21

人臉識別按鍵鍵盤

2021-10-29 07:49:22

Spring事務(wù)管理

2019-11-08 10:48:07

Windows操作系統(tǒng)微信Windows 10

2016-09-23 15:36:53

Windows10開始菜單程序

2020-05-09 16:45:56

ping命令Linux

2012-07-13 11:32:16

網(wǎng)絡(luò)出口

2020-09-14 11:26:54

BinlogCanal數(shù)據(jù)庫

2024-03-25 08:03:32

技術(shù)面試ShowMeBug協(xié)同編程

2024-10-28 07:10:00

scroll標記前端網(wǎng)格布局
點贊
收藏

51CTO技術(shù)棧公眾號

国产激情视频一区二区在线观看| 欧美日韩激情| 婷婷久久综合九色综合伊人色| 国产日韩在线一区二区三区| 无码人妻精品一区二区三区不卡| 国产一区二区三区电影在线观看| 欧美日韩视频专区在线播放| 欧美高清中文字幕| 黄色的视频在线免费观看| 久久99久久久久| 欧美激情国产精品| 成人乱码一区二区三区av| 四虎永久精品在线| 激情成人在线视频| 宅男噜噜99国产精品观看免费| 成 人片 黄 色 大 片| 免费在线播放第一区高清av| 色噜噜狠狠狠综合曰曰曰88av | 日日夜夜免费精品| 欧美成人一区二区三区电影| 亚洲av无码一区二区二三区| 日韩欧美一级| 欧美视频你懂的| 日本韩国欧美在线观看| 免费在线观看av| 久久久综合网站| 国产99午夜精品一区二区三区| 欧美成人一区二区三区四区| 欧美三级网页| 久久视频这里只有精品| 成人午夜福利一区二区| 一区二区三区在线资源| 欧美日韩国产高清一区二区| 97超碰青青草| 波多野结衣久久| 1000部国产精品成人观看| 精品国产_亚洲人成在线| 97成人免费视频| 国产精品毛片| 国语自产精品视频在免费| 老熟妇高潮一区二区三区| 欧洲grand老妇人| 日韩成人在线观看| 亚洲 欧美 日韩在线| 激情不卡一区二区三区视频在线| 91成人免费电影| 尤物av无码色av无码| 91精品久久| 亚洲色图欧美偷拍| 亚洲午夜精品一区二区| 岛国大片在线观看| 国产片一区二区| 欧美一区二区在线视频观看| 日本波多野结衣在线| 国产精品乡下勾搭老头1| 91天堂在线视频| 国产精品久久久久久久久毛片 | 欧美日韩在线中文字幕| 不卡av免费在线观看| 国产91aaa| 免费的黄色av| 不卡av在线免费观看| 国产中文一区二区| 亚洲日本香蕉视频| 久久久久久一二三区| 免费久久久一本精品久久区| 精品无人乱码| 亚洲国产成人午夜在线一区| 水蜜桃亚洲一二三四在线| 成年人在线观看网站| 国产精品网站导航| 麻豆一区二区三区在线观看| 天天色天天射天天综合网| 亚洲精品免费在线| 97超碰国产精品| 三级在线看中文字幕完整版| 一本色道久久综合亚洲91| mm1313亚洲国产精品无码试看| 国产一区二区三区影视| 欧美乱熟臀69xxxxxx| 日本55丰满熟妇厨房伦| 欧美色图五月天| 国产一区二区三区三区在线观看| 美国精品一区二区| 国产精品v亚洲精品v日韩精品| 久久久久久九九九| 青青草免费观看视频| 日本在线不卡视频一二三区| 91亚洲精品久久久| 日韩在线视频观看免费| 久久精品欧美一区二区三区不卡| 一区二区三区国| 精品精品导航| 欧美日韩中文字幕一区二区| 国产又黄又嫩又滑又白| 奇米影视777在线欧美电影观看| 亚洲天堂男人天堂| 丝袜美腿小色网| 亚洲东热激情| 国产免费成人av| 精品人妻一区二区三区四区不卡| 99免费精品视频| 亚洲一区精彩视频| free性欧美| 欧美日韩激情一区| 五月开心播播网| 91精品国偷自产在线电影| 97超碰国产精品女人人人爽 | 日韩精品在线免费观看| 亚洲精品自拍视频在线观看| 一区二区91| 亚洲一区精品电影| 韩日视频在线| 亚洲国产日产av| 日本在线播放一区二区| 思热99re视热频这里只精品| 精品国产一区二区三区在线观看| 国产精品suv一区二区三区| 精品无人区卡一卡二卡三乱码免费卡 | 久久久久88色偷偷免费| 国产精品自拍合集| 亚洲欧美专区| 在线视频免费一区二区| 天堂网av手机版| 国产白丝网站精品污在线入口| 亚洲欧美日韩国产yyy| 中文字幕高清在线播放| 精品久久久久久久久久久久久久久| 免费看91的网站| 亚洲日本激情| 成人欧美一区二区三区视频 | 77777少妇光屁股久久一区| 国产精品嫩草影院桃色| 亚洲国产精品激情在线观看| aa在线免费观看| 国产成人aa在线观看网站站| 久久伊人免费视频| 中文字幕一区二区在线视频| 久久精品一区蜜桃臀影院| 成人午夜免费在线| 99re8这里有精品热视频免费 | 激情综合网av| 亚洲欧美日韩精品综合在线观看 | 色素色在线综合| 波多野结衣av在线免费观看| 99亚洲伊人久久精品影院红桃| 波多野结衣成人在线| 手机在线免费观看av| 欧美一级片免费看| 精品人妻伦九区久久aaa片| 精品一区二区免费在线观看| 三区精品视频观看| 成人国产精品| 久久精品免费电影| 国产精品老熟女视频一区二区| 国产精品不卡视频| 亚洲一区二区三区观看| 综合天堂av久久久久久久| 91在线色戒在线| 成人黄色在线电影| 日韩欧美不卡在线观看视频| 久久这里只有精品国产| 成人精品视频一区二区三区 | 日韩精品一区二区三区在线播放| www.超碰在线观看| 国产成人免费视频精品含羞草妖精| 欧美在线观看视频免费| 狼人精品一区二区三区在线| 欧美亚洲日本黄色| 黄色毛片在线看| 欧美裸体bbwbbwbbw| 综合五月激情网| 成人午夜激情在线| 无码人妻h动漫| 久久国产成人精品| 999精品视频一区二区三区| 1024在线看片你懂得| 亚洲美女自拍视频| 一级片在线观看视频| 亚洲乱码国产乱码精品精98午夜| 香蕉视频污视频| 另类国产ts人妖高潮视频| 亚洲精品一卡二卡三卡四卡| 久久中文字幕一区二区| 97香蕉超级碰碰久久免费的优势| 黄色av网站在线| 欧美高清www午色夜在线视频| 久久影院一区二区| 国产日韩av一区二区| 在线成人免费av| 午夜亚洲性色福利视频| 在线观看亚洲视频啊啊啊啊| 岛国成人av| 日韩美女主播视频| 大片免费在线看视频| 日韩精品免费在线视频| 国产一区二区三区在线观看| 亚洲va国产天堂va久久en| 久久久久久久久福利| 福利视频网站一区二区三区| 久草在在线视频| 国内综合精品午夜久久资源| 欧美精品一区在线| 中文一区二区三区四区| 国产精品18久久久久久麻辣| 国产盗摄一区二区| www高清在线视频日韩欧美| 日韩一级中文字幕| 91精品麻豆日日躁夜夜躁| 免费看日批视频| 亚洲自拍偷拍综合| 国产小视频你懂的| 久久久天堂av| 亚洲色偷偷色噜噜狠狠99网| 美女精品一区二区| 国产成人a亚洲精v品无码| 欧美 日韩 国产精品免费观看| 日本中文不卡| 日韩影视高清在线观看| 91久久夜色精品国产网站| 日韩大尺度黄色| 国语自产在线不卡| av中文字幕在线观看| 中文字幕日韩在线观看| 性高潮久久久久久久久久| 日韩欧美成人激情| 国产免费福利视频| 欧美裸体一区二区三区| 精品国产青草久久久久96| 疯狂做受xxxx欧美肥白少妇| 国产无套粉嫩白浆内谢| 一区二区三区日本| 希岛爱理中文字幕| 国产精品丝袜一区| 亚洲一二三四视频| 国产女主播一区| 中文字幕免费高清| 久久久99久久| 欧美日韩高清丝袜| 26uuu久久天堂性欧美| 99re久久精品国产| 99热精品国产| 中文在线永久免费观看| 成人v精品蜜桃久久一区| 国产a级片视频| 成人高清在线视频| 日本一卡二卡在线| 成人精品免费看| 亚洲国产综合视频| 91女神在线视频| 欧美成人午夜精品免费| 久久久高清一区二区三区| 精品人妻无码一区二区三区换脸 | 中文字幕乱码av| 国产精品久久精品日日| 激情五月激情综合| 亚洲黄色在线视频| 国产主播在线观看| 精品久久久久久久久久| 一二三区免费视频| 欧美日韩在线播放| 国产女同91疯狂高潮互磨| 欧美电影一区二区| www国产在线| 亚洲成人999| 男人的天堂在线视频| 国产亚洲欧美另类中文| 日本黄色片在线观看| 久久精品亚洲一区| 欧美78videosex性欧美| 欧美亚洲另类激情另类| 日本精品另类| 亚洲最大福利网| 欧美美女在线直播| 欧美激情www| 久久久久久久久久久妇女| 九九久久九九久久| 亚洲中午字幕| 色一情一区二区| 成人激情小说网站| 免费看91的网站| 亚洲综合免费观看高清完整版 | 日韩美女视频在线| 亚洲三区在线观看无套内射| 国产一区二区三区在线看 | 97视频色精品| 视频精品导航| 国产女主播一区二区三区| 精品国精品国产自在久国产应用| 丰满女人性猛交| 亚洲欧美日韩一区在线观看| 国产色视频在线播放| 成人性色生活片| 色偷偷男人天堂| 午夜激情综合网| 91福利在线观看视频| 亚洲成人网av| 亚洲成人三级| 91成人福利在线| 日韩有吗在线观看| 亚洲看片网站| aa亚洲婷婷| 欧美日韩理论片| 国产性做久久久久久| 精品一区免费观看| 欧美精品一二三区| 视频一区二区在线播放| 欧美日韩福利电影| 国产精品久久久久久久久免费高清 | 欧美又粗又长又爽做受| 蜜桃一区二区三区四区| 国产一级二级视频| 一区二区欧美国产| 中文字幕一区二区人妻痴汉电车 | 91在线网址| 26uuu另类亚洲欧美日本一| 美女国产精品久久久| 亚洲精品一区二区三区四区五区| 国产欧美日本| 艳妇乳肉豪妇荡乳xxx| 亚洲免费大片在线观看| 国产成人自拍偷拍| 亚洲老头老太hd| 91丝袜在线| 成人欧美一区二区| 欧美欧美全黄| 国产aⅴ爽av久久久久| 国产精品午夜在线观看| 丰满少妇xoxoxo视频| 日韩av在线网页| 岛国片av在线| 99久久国产免费免费| 91成人看片| 国产色视频在线播放| 国产精品亲子伦对白| 久久久国产免费| 亚洲欧美在线免费| 大胆人体一区| 免费看国产精品一二区视频| 99日韩精品| 丝袜美腿中文字幕| 日韩欧美在线视频日韩欧美在线视频| 日本免费一区视频| 91国内在线视频| 图片婷婷一区| 激情五月开心婷婷| 国产午夜精品久久久久久免费视| 香蕉影院在线观看| 亚洲午夜av久久乱码| 欧美三区四区| 视频一区在线免费观看| 免费国产亚洲视频| 免费一级suv好看的国产网站| 欧美丝袜丝nylons| 在线a免费看| 成人在线国产精品| 综合视频在线| 少妇一级淫片免费放播放| 午夜视频一区在线观看| 无码国产精品一区二区免费16| 91干在线观看| 欧美日中文字幕| 欧美日韩精品区别| 亚洲免费av在线| 男人天堂av网| 欧美在线观看网址综合| 精品国产一区探花在线观看| 九九精品久久久| 亚洲一区二区在线免费观看视频| 亚洲免费黄色片| 日韩av电影手机在线观看| 成人黄色小视频| 99视频在线观看视频| 亚洲第一av色| 成人在线免费观看| 亚洲va久久久噜噜噜久久天堂| 一区二区三区精品视频在线观看| 人人人妻人人澡人人爽欧美一区| 3atv在线一区二区三区| 精品极品在线| 亚洲综合激情五月| 菠萝蜜视频在线观看一区| 中文字幕一区二区三区人妻四季| 欧美美女操人视频| 精品国产中文字幕第一页| 超碰人人cao| 在线观看亚洲精品| 亚洲图区一区| 午夜精品短视频| 成人一道本在线| 在线观看黄色网| 久久久噜噜噜久久久| 日韩国产一区二区| 亚洲高清无码久久| 欧美久久久久久久久中文字幕| 成人超碰在线| 亚洲蜜桃av| 91免费国产在线| 亚洲h视频在线观看| 国产美女主播一区|