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

聊一聊 15.5K 的 FileSaver,是如何工作的?

系統 瀏覽器
FileSaver.js 是在客戶端保存文件的解決方案,非常適合在客戶端上生成文件的 Web 應用程序。

[[354383]]

本文轉載自微信公眾號「全棧修仙之路」,作者阿寶哥。轉載本文請聯系全棧修仙之路公眾號。  

FileSaver.js 是在客戶端保存文件的解決方案,非常適合在客戶端上生成文件的 Web 應用程序。它簡單易用且兼容大多數瀏覽器,被作為項目依賴應用在 6.3 萬的項目中。在近期的項目中,阿寶哥再一次使用到了它,所以就想寫篇文章來聊一聊這個優秀的開源項目。

一、FileSaver.js 簡介

FileSaver.js 是 HTML5 的 saveAs() FileSaver 實現。它支持大多數主流的瀏覽器,其兼容性如下圖所示:

 

(圖片來源:https://github.com/eligrey/FileSaver.js)

1.1 saveAs API

  1. FileSaver saveAs(Blob/File/Url, optional DOMString filename, optional Object { autoBom }) 

saveAs 方法支持三個參數,第一個參數表示它支持 Blob/File/Url 三種類型,第二個參數表示文件名(可選),而第三個參數表示配置對象(可選)。如果你需要 FlieSaver.js 自動提供 Unicode 文本編碼提示(參考:字節順序標記),則需要設置 { autoBom: true}。

1.2 保存文本

let blob = new Blob(["大家好,我是阿寶哥!"], { type: "text/plain;charset=utf-8" });FileSaver.saveAs(blob, "hello.txt");

1.3 保存線上資源

  1. FileSaver saveAs(Blob/File/Url, optional DOMString filename, optional Object { autoBom }) 

如果下載的 URL 地址與當前站點是同域的,則將使用 a[download] 方式下載。否則,會先使用 同步的 HEAD 請求 來判斷是否支持 CORS 機制,若支持的話,將進行數據下載并使用 Blob URL 實現文件下載。如果不支持 CORS 機制的話,將會嘗試使用 a[download] 方式下載。

標準的 W3C File API Blob 接口并非在所有瀏覽器中都可用,對于這個問題,你可以考慮使用 Blob.js 來解決兼容性問題。

 

(圖片來源:https://caniuse.com/?search=blob)

1.4 保存 Canvas 畫布內容

  1. let canvas = document.getElementById("my-canvas"); 
  2. canvas.toBlob(function(blob) { 
  3.   saveAs(blob, "abao.png"); 
  4. }); 

需要注意的是 canvas.toBlob() 方法并非在所有瀏覽器中都可用,對于這個問題,你可以考慮使用 canvas-toBlob.js 來解決兼容性問題。

 

(圖片來源:https://caniuse.com/?search=toBlob)

在以上的示例中,我們多次見到 Blob 的身影,因此在介紹 FileSaver.js 源碼時,阿寶哥先來簡單介紹一下 Blob 的相關知識。

二、Blob 簡介

Blob(Binary Large Object)表示二進制類型的大對象。在數據庫管理系統中,將二進制數據存儲為一個單一個體的集合。Blob 通常是影像、聲音或多媒體文件。在 JavaScript 中 Blob 類型的對象表示不可變的類似文件對象的原始數據。

2.1 Blob 構造函數

Blob 由一個可選的字符串 type(通常是 MIME 類型)和 blobParts 組成:

 

MIME(Multipurpose Internet Mail Extensions)多用途互聯網郵件擴展類型,是設定某種擴展名的文件用一種應用程序來打開的方式類型,當該擴展名文件被訪問的時候,瀏覽器會自動使用指定應用程序來打開。多用于指定一些客戶端自定義的文件名,以及一些媒體文件打開方式。

常見的 MIME 類型有:超文本標記語言文本 .html text/html、PNG 圖像 .png image/png、普通文本 .txt text/plain 等。

在 JavaScript 中我們可以通過 Blob 的構造函數來創建 Blob 對象,Blob 構造函數的語法如下:

  1. var aBlob = new Blob(blobParts, options); 

相關的參數說明如下:

  • blobParts:它是一個由 ArrayBuffer,ArrayBufferView,Blob,DOMString 等對象構成的數組。DOMStrings 會被編碼為 UTF-8。
  • options:一個可選的對象,包含以下兩個屬性:
    • type —— 默認值為 "",它代表了將會被放入到 blob 中的數組內容的 MIME 類型。
    • endings —— 默認值為 "transparent",用于指定包含行結束符 \n 的字符串如何被寫入。它是以下兩個值中的一個:"native",代表行結束符會被更改為適合宿主操作系統文件系統的換行符,或者 "transparent",代表會保持 blob 中保存的結束符不變。

介紹完 Blob 之后,我們再來介紹一下 Blob URL。

2.2 Blob URL

Blob URL/Object URL 是一種偽協議,允許 Blob 和 File 對象用作圖像,下載二進制數據鏈接等的 URL 源。在瀏覽器中,我們使用 URL.createObjectURL 方法來創建 Blob URL,該方法接收一個 Blob 對象,并為其創建一個唯一的 URL,其形式為 blob:/,對應的示例如下:

blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f641

瀏覽器內部為每個通過 URL.createObjectURL 生成的 URL 存儲了一個 URL → Blob 映射。因此,此類 URL 較短,但可以訪問 Blob。生成的 URL 僅在當前文檔打開的狀態下才有效。它允許引用 中的 Blob,但如果你訪問的 Blob URL 不再存在,則會從瀏覽器中收到 404 錯誤。

上述的 Blob URL 看似很不錯,但實際上它也有副作用。雖然存儲了 URL → Blob 的映射,但 Blob 本身仍駐留在內存中,瀏覽器無法釋放它。映射在文檔卸載時自動清除,因此 Blob 對象隨后被釋放。但是,如果應用程序壽命很長,那不會很快發生。因此,如果我們創建一個 Blob URL,即使不再需要該 Blob,它也會存在內存中。

針對這個問題,我們可以調用 URL.revokeObjectURL(url) 方法,從內部映射中刪除引用,從而允許刪除 Blob(如果沒有其他引用),并釋放內存。

好的,現在我們已經介紹了 Blob 和 Blob URL。如果你還意猶未盡,想深入理解 Blob 的話,可以閱讀 你不知道的 Blob 這篇文章,接下來我們開始分析 FileSaver.js 的源碼。

三、FileSaver.js 源碼解析

在 FileSaver.js 內部提供了三種方案來實現文件保存,因此接下來我們將分別來介紹這三種方案。

3.1 方案一

當 FileSaver.js 在保存文件時,如果當前平臺中 a 標簽支持 download 屬性且非 MacOS WebView 環境,則會優先使用 a[download] 來實現文件保存。在具體使用過程中,我們是通過調用 saveAs 方法來保存文件,該方法的定義如下:

  1. FileSaver saveAs(Blob/File/Url, optional DOMString filename, optional Object { autoBom }) 

通過觀察 saveAs 方法的簽名,我們可知該方法支持字符串和 Blob 兩種類型的參數,因此在 saveAs 方法內部需要分別處理這兩種類型的參數,下面我們先來分析字符串參數的情形。

3.1.1 字符串類型參數

在前面的示例中,我們演示了如何利用 saveAs 方法來保存線上的圖片:

  1. FileSaver.saveAs("https://httpbin.org/image""image.jpg"); 

在方案一中,saveAs 方法的處理邏輯如下所示:

  1. // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView 
  2. function saveAs(blob, name, opts) { 
  3.   var URL = _global.URL || _global.webkitURL; 
  4.   var a = document.createElement("a"); 
  5.   name = name || blob.name || "download"
  6.  
  7.   a.download = name
  8.   a.rel = "noopener"
  9.  
  10.   if (typeof blob === "string") { 
  11.     a.href = blob; 
  12.     if (a.origin !== location.origin) { // (1) 
  13.       corsEnabled(a.href) 
  14.         ? download(blob, name, opts) 
  15.         : click(a, (a.target = "_blank")); 
  16.     } else { // (2) 
  17.       click(a); 
  18.     } 
  19.   } else { 
  20.     // 省略處理Blob類型參數 
  21.   } 

在以上代碼中,如果發現下載資源的 URL 地址與當前站點是非同域的,則會先使用 同步的 HEAD 請求 來判斷是否支持 CORS 機制,若支持的話,就會調用 download 方法進行文件下載。首先我們先來分析 corsEnabled 方法:

  1. function corsEnabled(url) { 
  2.   var xhr = new XMLHttpRequest(); 
  3.   xhr.open("HEAD", url, false); 
  4.   try { 
  5.     xhr.send(); 
  6.   } catch (e) {} 
  7.   return xhr.status >= 200 && xhr.status <= 299; 

corsEnabled 方法的實現很簡單,就是通過 XMLHttpRequest API 發起一個同步的 HEAD 請求,然后判斷返回的狀態碼是否在 [200 ~ 299] 的范圍內。接著我們來看一下download 方法的具體實現:

  1. function download(url, name, opts) { 
  2.   var xhr = new XMLHttpRequest(); 
  3.   xhr.open("GET", url); 
  4.   xhr.responseType = "blob"
  5.   xhr.onload = function () { 
  6.     saveAs(xhr.response, name, opts); 
  7.   }; 
  8.   xhr.onerror = function () { 
  9.     console.error("could not download file"); 
  10.   }; 
  11.   xhr.send(); 

同樣 download 方法的實現也很簡單,也是通過 XMLHttpRequest API 來發起 HTTP 請求,與大家熟悉的 JSON 格式不同的是,我們需要設置 responseType 的類型為 blob。此外,因為返回的結果是 blob 類型的數據,所以在成功回調函數內部會繼續調用 saveAs方法來實現文件保存。

而對于不支持 CORS 機制或同域的情形,它會調用內部的 click 方法來完成下載功能,該方法的具體實現如下:

  1. // `a.click()` doesn't work for all browsers (#465) 
  2. function click(node) { 
  3.   try { 
  4.     node.dispatchEvent(new MouseEvent("click")); 
  5.   } catch (e) { 
  6.     var evt = document.createEvent("MouseEvents"); 
  7.     evt.initMouseEvent( 
  8.       "click"truetrue, window, 0, 0, 0, 80, 20,  
  9.       falsefalsefalsefalse, 0, null 
  10.     ); 
  11.     node.dispatchEvent(evt); 
  12.   } 

在 click 方法內部,會優先調用 node 對象上的 dispatchEvent 方法來派發 click 事件。當出現異常的時候,會在 catch 語句進行相應的異常處理,catch 語句中的 MouseEvent.initMouseEvent() 方法用于初始化鼠標事件的值。但需要注意的是,該特性已經從 Web 標準中刪除,雖然一些瀏覽器目前仍然支持它,但也許會在未來的某個時間停止支持,請盡量不要使用該特性。

3.1.2 blob 類型參數

同樣,在前面的示例中,我們演示了如何利用 saveAs 方法來保存 Blob 類型數據:

  1. let blob = new Blob(["大家好,我是阿寶哥!"], { type: "text/plain;charset=utf-8" }); 
  2. FileSaver.saveAs(blob, "hello.txt"); 

blob 類型參數的處理邏輯,被定義在 saveAs 方法體的 else 分支中:

  1. // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView 
  2. function saveAs(blob, name, opts) { 
  3.   var URL = _global.URL || _global.webkitURL; 
  4.   var a = document.createElement("a"); 
  5.   name = name || blob.name || "download"
  6.  
  7.   a.download = name
  8.   a.rel = "noopener"
  9.  
  10.   if (typeof blob === "string") { 
  11.      // 省略處理字符串類型參數 
  12.   } else { 
  13.     a.href = URL.createObjectURL(blob); 
  14.     setTimeout(function () { 
  15.       URL.revokeObjectURL(a.href); 
  16.     }, 4e4); // 40s 
  17.     setTimeout(function () { 
  18.       click(a); 
  19.     }, 0); 
  20.   } 

對于 blob 類型的參數,首先會通過 createObjectURL 方法來創建 Object URL,然后在通過 click 方法執行文件保存。為了能及時釋放內存,在 else 處理分支中,會啟動一個定時器來執行清理操作。此時,方案一我們已經介紹完了,接下去要介紹的方案二主要是為了兼容 IE 瀏覽器。

3.2 方案二

在 Internet Explorer 10 瀏覽器中,msSaveBlob 和 msSaveOrOpenBlob 方法允許用戶在客戶端上保存文件,其中 msSaveBlob 方法只提供一個保存按鈕,而 msSaveOrOpenBlob 方法提供了保存和打開按鈕,對應的使用方式如下所示:

  1. window.navigator.msSaveBlob(blobObject, 'msSaveBlob_hello.txt'); 
  2. window.navigator.msSaveOrOpenBlob(blobObject, 'msSaveBlobOrOpenBlob_hello.txt'); 

了解完上述的知識和方案一中介紹的 corsEnabled、download 和 click 方法后,再來看方案二的代碼,就很清晰明了。

在滿足 "msSaveOrOpenBlob" in navigator 條件時, FileSaver.js 會使用方案二來實現文件保存。跟前面一樣,我們先來分析 字符串類型參數 的處理邏輯。

3.2.1 字符串類型參數

  1. // Use msSaveOrOpenBlob as a second approach 
  2. function saveAs(blob, name, opts) { 
  3.   name = name || blob.name || "download"
  4.   if (typeof blob === "string") { 
  5.     if (corsEnabled(blob)) { // 判斷是否支持CORS 
  6.       download(blob, name, opts); 
  7.     } else { 
  8.       var a = document.createElement("a"); 
  9.       a.href = blob; 
  10.       a.target = "_blank"
  11.       setTimeout(function () { 
  12.         click(a); 
  13.       }); 
  14.     } 
  15.   } else { 
  16.     // 省略處理Blob類型參數 
  17.   } 

3.2.2 blob 類型參數

  1. // Use msSaveOrOpenBlob as a second approach 
  2. function saveAs(blob, name, opts) { 
  3.   name = name || blob.name || "download"
  4.   if (typeof blob === "string") { 
  5.     // 省略處理字符串類型參數 
  6.   } else { 
  7.     navigator.msSaveOrOpenBlob(bom(blob, opts), name); // 提供了保存和打開按鈕 
  8.   } 

3.3 方案三

如果方案一和方案二都不支持的話,FileSaver.js 就會降級使用 FileReader API 和 open API 新開窗口來實現文件保存。

3.3.1 字符串類型參數

  1. // Fallback to using FileReader and a popup 
  2. function saveAs(blob, name, opts, popup) { 
  3.   // Open a popup immediately do go around popup blocker 
  4.   // Mostly only available on user interaction and the fileReader is async so... 
  5.   popup = popup || open("""_blank"); 
  6.   if (popup) { 
  7.     popup.document.title = popup.document.body.innerText = "downloading..."
  8.   } 
  9.  
  10.   if (typeof blob === "string"return download(blob, name, opts); 
  11.  // 處理Blob類型參數 

3.3.2 blob 類型參數

對于 blob 類型的參數來說,在 saveAs 方法內部會根據不同的環境選用不同的方案,比如在 Safari 瀏覽器環境中,它會利用 FileReader API 先把 Blob 對象轉換為 Data URL,然后再把該 Data URL 地址賦值給新開的窗口或當前窗口的 location 對象,具體的代碼如下:

  1. // Fallback to using FileReader and a popup 
  2. function saveAs(blob, name, opts, popup) { 
  3.   // Open a popup immediately do go around popup blocker 
  4.   // Mostly only available on user interaction and the fileReader is async so... 
  5.   popup = popup || open("""_blank"); 
  6.   if (popup) { // 設置新開窗口的標題 
  7.     popup.document.title = popup.document.body.innerText = "downloading..."
  8.   } 
  9.  
  10.   if (typeof blob === "string"return download(blob, name, opts); 
  11.  
  12.   var force = blob.type === "application/octet-stream"; // 二進制流數據 
  13.   var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari; 
  14.   var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); 
  15.  
  16.   if ( 
  17.     (isChromeIOS || (force && isSafari) || isMacOSWebView) && 
  18.     typeof FileReader !== "undefined" 
  19.   ) { 
  20.     // Safari doesn't allow downloading of blob URLs 
  21.     var reader = new FileReader(); 
  22.     reader.onloadend = function () { 
  23.       var url = reader.result; 
  24.       url = isChromeIOS 
  25.         ? url 
  26.         : url.replace(/^data:[^;]*;/, "data:attachment/file;"); // 處理成附件的形式 
  27.       if (popup) popup.location.href = url; 
  28.       else location = url; 
  29.       popup = null; // reverse-tabnabbing #460 
  30.     }; 
  31.     reader.readAsDataURL(blob); 
  32.   } else { 
  33.     // 省略Object URL的處理邏輯 
  34.   } 

其實對于 FileReader API 來說,除了支持把 File/Blob 對象轉換為 Data URL 之外,它還提供了 readAsArrayBuffer() 和 readAsText() 方法,用于把 File/Blob 對象轉換為其它的數據格式。

在 玩轉前端二進制 文章中,阿寶哥詳細介紹了 FileReader API 在前端圖片處理場景中的應用,閱讀完該文章之后,你們將能輕松看懂以下轉換關系圖:

 

最后我們再來看一下 else 分支的代碼:

  1. function saveAs(blob, name, opts, popup) { 
  2.   popup = popup || open("""_blank"); 
  3.   if (popup) { 
  4.     popup.document.title = popup.document.body.innerText = "downloading..."
  5.   } 
  6.  
  7.   // 處理字符串類型參數 
  8.   if (typeof blob === "string"return download(blob, name, opts); 
  9.  
  10.   if ( 
  11.     (isChromeIOS || (force && isSafari) || isMacOSWebView) && 
  12.     typeof FileReader !== "undefined" 
  13.   ) { 
  14.     // 省略FileReader API處理邏輯 
  15.   } else { 
  16.     var URL = _global.URL || _global.webkitURL; 
  17.     var url = URL.createObjectURL(blob); 
  18.     if (popup) popup.location = url; 
  19.     else location.href = url; 
  20.     popup = null; // reverse-tabnabbing #460 
  21.     setTimeout(function () { 
  22.       URL.revokeObjectURL(url); 
  23.     }, 4e4); // 40s 
  24.   } 

到這里 FileSaver.js 這個庫的源碼已經分析完成了,跟著阿寶哥閱讀上述源碼之后,是不是覺得寫一個兼容性好、簡單易用的第三方庫是多么不容易。

 

在實際項目中,如果你需要保存超過 blob 大小限制的超大文件,或者沒有足夠的內存空間,你可以考慮使用更高級的 StreamSaver.js 庫來實現文件保存功能。

 

責任編輯:武曉燕 來源: 全棧修仙之路
相關推薦

2023-03-05 18:40:39

iptables防火墻軟件

2023-10-24 15:56:23

2021-06-29 08:45:55

邏輯變量法函數

2022-08-22 09:20:05

Kubernetes工作負載管理

2023-07-06 13:56:14

微軟Skype

2020-09-08 06:54:29

Java Gradle語言

2020-01-07 08:31:52

代碼分層Web

2024-10-28 21:02:36

消息框應用程序

2021-08-01 09:55:57

Netty時間輪中間件

2023-09-27 16:39:38

2020-12-29 05:33:40

TomcatSpringBoot代碼

2025-02-18 00:00:05

vue后端權限

2023-09-20 23:01:03

Twitter算法

2021-12-06 09:43:01

鏈表節點函數

2021-07-16 11:48:26

模型 .NET微軟

2021-03-01 18:37:15

MySQL存儲數據

2018-05-16 08:58:04

用戶畫像存儲

2023-11-02 08:37:46

Python換行轉義

2020-12-11 11:11:44

原子類JavaCAS

2022-08-30 07:39:57

C++namespace隔離
點贊
收藏

51CTO技術棧公眾號

在线观看h网| 亚洲专区第一页| 自拍偷拍欧美一区| 在线观看亚洲a| 亚洲黄色网址在线观看| 人人妻人人玩人人澡人人爽| 亚洲永久免费| 精品国产欧美一区二区三区成人| 美女又黄又免费的视频| 国产精品av一区二区三区| 国产精品久久久久7777按摩| 国产伦精品一区二区三区免| 最近中文字幕在线视频| 欧美特黄一区| 色一情一乱一区二区| 妖精视频在线观看| 福利精品在线| 欧美日韩久久久久| 国产又粗又大又爽的视频| 深夜福利在线视频| 国产美女久久久久| 国产成人精品电影| 国产亚洲精品女人久久久久久| 少妇精品久久久| 欧美mv日韩mv亚洲| www.com黄色片| 91av亚洲| 亚洲1区2区3区视频| 一区二区精品视频| 国产小视频免费在线观看| 成人h动漫精品| 亚洲一区二区三区777| 一区精品在线观看| 免费看的黄色欧美网站| 欧美黑人一区二区三区 | 成人h精品动漫一区二区三区| 国产精品自产拍高潮在线观看| 精品在线播放视频| 国产精品99一区二区| 精品国产一区二区三区久久久| 蜜桃传媒一区二区亚洲av| www国产精品| 日韩免费电影网站| 91欧美一区二区三区| 九七影院97影院理论片久久| 91福利区一区二区三区| 亚洲 高清 成人 动漫| 波多野结衣精品| 亚洲国产精品天堂| 97碰在线视频| 欧美aaaaaaa| 一区二区三区四区视频精品免费 | 欧美中文字幕一区二区三区| 欧美污视频网站| 少妇视频一区| 欧美三级免费观看| 国产a级一级片| 亚洲精品一区| 在线欧美一区二区| 一区二区三区入口| 日韩成人在线电影| 欧美日本一区二区三区四区 | www成人在线| 中日韩视频在线观看| 2020国产精品视频| 国产精品免费精品一区| 久久精品成人| 国产精品揄拍一区二区| 中文字幕激情视频| 国产一区视频网站| 成人9ⅰ免费影视网站| 婷婷综合激情网| 久久亚洲精品小早川怜子| 欧美在线视频一区二区三区| 9191在线| 一区二区三区精品| 91免费视频网站在线观看| 欧美极度另类| 在线成人av网站| 野战少妇38p| 亚洲欧美tv| 色婷婷成人综合| 美女视频黄免费| av成人国产| 国产欧美久久一区二区| 精品国产av 无码一区二区三区| 国产一区二区看久久| 黄色一区三区| 18视频免费网址在线观看| 亚洲免费观看视频| 色欲av无码一区二区人妻| 欧美xxxx性| 亚洲国产精品成人va在线观看| 波多野结衣影院| 日韩1区在线| 97国产精品视频| 中文字幕永久免费视频| 成人在线一区二区三区| 免费在线观看91| aaa大片在线观看| 午夜不卡av免费| 亚洲一区精品视频在线观看| 国内毛片久久| www.日韩欧美| 久久黄色精品视频| 国产美女娇喘av呻吟久久 | 久久一区91| 午夜精品一区二区三区av| 姑娘第5集在线观看免费好剧| 国产成人综合在线播放| 日韩精品久久一区| 91探花在线观看| 欧美久久久久中文字幕| 欧美亚一区二区三区| 伊人久久大香线蕉综合四虎小说 | 一级片中文字幕| 国产一区二区福利| 神马影院午夜我不卡影院| 爱搞国产精品| 日韩三级在线观看| 亚洲一二三四视频| 久久动漫亚洲| 国产一区喷水| 日本小视频在线免费观看| 欧美日韩精品系列| 欧美黄色激情视频| 香蕉av777xxx色综合一区| av成人午夜| a视频在线免费看| 欧美日韩视频专区在线播放| 亚洲国产无码精品| 99综合视频| 国产亚洲二区| 999精品网| 精品国产免费一区二区三区香蕉| 二区三区四区视频| 理论电影国产精品| 亚洲乱码一区二区三区三上悠亚| 中文字幕一区久| 日韩禁在线播放| 五月天婷婷网站| 成人精品鲁一区一区二区| 精品人妻人人做人人爽| 日韩欧美一级| 久久99热精品| 亚洲欧美另类一区| 亚洲自拍偷拍麻豆| 制服丝袜在线第一页| 伊人久久亚洲美女图片| 国产精品国产精品国产专区不卡| 曰本三级在线| 欧美r级电影在线观看| 久久久国产精华液| 成年人国产精品| 精品这里只有精品| 一道在线中文一区二区三区| 欧美在线视频导航| 国产乱视频在线观看| 欧美综合亚洲图片综合区| 日本成人免费在线观看| 精品一区二区av| 五月天激情图片| 中文字幕一区日韩精品| 午夜精品一区二区三区在线播放| 人妻丰满熟妇av无码区hd| 亚洲成av人片在线| 亚洲第一页av| 日韩精品1区2区3区| 中文字幕欧美人与畜| 美女精品久久| 97久久精品国产| 毛片免费在线观看| 在线播放中文一区| 久久久综合久久| 久久亚洲影视婷婷| 亚洲视频一二三四| 国产一区二区三区四区老人| 久久久99爱| 日韩经典一区| 欧美第一黄色网| 日韩电影在线观看完整版| 欧美在线观看视频在线| 亚洲欧美一区二区三区四区五区| 不卡视频免费播放| 韩国中文字幕av| 欧美破处大片在线视频| 久久久久久久免费| www一区二区三区| 国语自产在线不卡| 成人77777| 精品99久久久久久| 国模私拍一区二区| 亚洲综合色网站| 国产又黄又粗的视频| 国产宾馆实践打屁股91| 青青草av网站| 黄色精品免费| 一区二区免费电影| 亚洲成a人片77777在线播放 | 日韩高清三区| 国产日韩专区在线| 特黄毛片在线观看| 久久成人av网站| 福利视频在线导航| 亚洲精品一区二区三区蜜桃下载| 中文字幕 国产精品| 亚洲大片精品永久免费| 精品国产国产综合精品| 久久综合狠狠综合久久激情| 爱情岛论坛亚洲自拍| 日韩成人精品在线观看| 黄色一级视频在线播放| 91超碰国产精品| 欧美在线激情| 三级小说欧洲区亚洲区| 成人一区二区在线| 日本成人一区二区| 国产精品成人一区| 妞干网免费在线视频| 欧美男插女视频| 男人天堂手机在线| 一本色道久久88综合日韩精品| 亚洲春色一区二区三区| 5月丁香婷婷综合| 亚洲中文无码av在线| 色哟哟一区二区在线观看| 国产亚洲欧美久久久久| 国产精品国产精品国产专区不蜜| 国产美女精品久久| 91丨九色丨蝌蚪丨老版| 亚洲婷婷在线观看| 国产91对白在线观看九色| 涩多多在线观看| 久久成人免费网站| 天天干天天草天天| 日本91福利区| 999精品视频在线| 日韩成人伦理电影在线观看| 国产黄色特级片| 久久青草久久| 日日摸日日碰夜夜爽av| 日韩一区二区久久| 可以在线看的av网站| 亚洲日本视频| 免费一级特黄毛片| 一本色道久久综合一区| 欧美精品一区二区三区三州| 伊人久久成人| 每日在线更新av| 久热精品视频| 91视频免费版污| 美洲天堂一区二卡三卡四卡视频| 欧美日韩怡红院| 蜜臀久久99精品久久久久久9 | 亚洲欧美国产精品va在线观看| 天堂a√在线| 亚洲欧美资源在线| 第九色区av在线| 日韩专区在线观看| 91高清在线观看视频| 欧美高清在线观看| 91在线三级| 国产91色在线|| 久久69成人| 亚洲在线免费看| 国产欧美三级电影| 欧美精品亚洲精品| 精品国产一区二区三区香蕉沈先生| 亚洲成人av动漫| 一区二区电影| 霍思燕三级露全乳照| 久久亚洲精选| 国产精品嫩草影院8vv8| 国产电影一区在线| 手机在线看片日韩| 国产精品免费视频一区| 久久高清无码视频| 日韩欧美综合在线视频| 中国一级片黄色一级片黄| 91精品国产综合久久精品麻豆| 亚洲黄色小说网| 亚洲人成免费电影| 成a人片在线观看| 午夜精品一区二区三区av| 国产综合色在线观看| 97超碰在线播放| 香蕉久久99| 裸体裸乳免费看| 国产精品日韩久久久| 婷婷激情四射五月天| 东方aⅴ免费观看久久av| 四虎国产精品成人免费入口| 亚洲精品视频免费观看| 亚洲 欧美 成人| 日韩欧美一区电影| 免费国产在线视频| 欧美激情在线狂野欧美精品| 成人日韩在线观看| 国产69精品久久久久9999apgf | av男人天堂一区| 999久久久国产| 欧美日韩亚洲国产一区| 亚洲在线免费观看视频| 亚洲男人天堂视频| 丁香影院在线| 成人黄色av网站| 亚洲欧洲免费| 国产精品一线二线三线| 精品一二线国产| av电影网站在线观看| 五月婷婷激情综合网| av中文在线观看| 在线激情影院一区| 亚洲最新无码中文字幕久久| 成人av影视在线| 亚洲大全视频| 久久久久久久久久久久91| 9i在线看片成人免费| 九九免费精品视频| 8v天堂国产在线一区二区| 国产一级片在线| 国产91精品久久久久久久| 亚洲小说春色综合另类电影| 在线观看成人av电影| 日本少妇一区二区| xxxx日本免费| 欧美性生交大片免网| 人妻与黑人一区二区三区| 欧美华人在线视频| 伊人久久亚洲| 无码人妻精品一区二区蜜桃百度| 久久精品国产久精国产| 免费视频91蜜桃| 色狠狠综合天天综合综合| 五月婷婷六月激情| 国内精品中文字幕| 草草视频在线一区二区| 337p亚洲精品色噜噜狠狠p| 国产在线精品免费| 免费成年人视频在线观看| 欧美精品久久一区| 久久日韩视频| 成人日韩在线电影| 亚洲啊v在线观看| 激情图片中文字幕| 亚洲色大成网站www久久九九| 亚洲一级片免费看| www.亚洲男人天堂| 天天综合91| 精品一区二区成人免费视频| 国产在线播放一区二区三区| 久久国产波多野结衣| 欧美一区二区视频在线观看| 中文字幕伦理免费在线视频| av日韩免费电影| 国产欧美成人| 偷拍夫妻性生活| 欧美日韩一级二级| 男人的天堂在线视频免费观看| 国产欧美最新羞羞视频在线观看| 欧美激情欧美| 激情成人在线观看| 亚洲电影第三页| 男女av在线| 国产欧美久久久久久| 国产精品激情电影| 亚洲制服丝袜在线播放| 在线精品视频一区二区三四| 午夜在线小视频| 成人免费视频观看视频| 亚洲综合国产| 美女av免费看| 日韩美女主播在线视频一区二区三区| 国产精品国精产品一二| 欧美激情www| 精品一区二区三区免费视频| 久久精品国产亚洲av麻豆色欲| 亚洲精品电影在线| 成人av色网站| 欧美日韩视频免费| 久久久精品人体av艺术| 99国产精品久久久久久久成人| 97精品国产97久久久久久| 欧美在线色图| 一本色道久久hezyo无码| 欧美中文字幕不卡| 黑人玩欧美人三根一起进| 日本午夜精品一区二区| 国产一区二区导航在线播放| 在线观看精品国产| 精品国产一区二区三区久久狼黑人 | av网站大全在线观看| 亚洲影院高清在线| 久久久蜜桃一区二区人| 中文字幕手机在线观看| 亚洲美女在线观看| 日韩中文字幕| 久草福利视频在线| 亚洲3atv精品一区二区三区| 免费人成在线观看播放视频|