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

Node.js中實現HTTP 206內容分片

開發 前端
在本文中,我會闡述HTTP狀態206 分部分內容 的基礎概念,并使用Node.js一步步地實現它. 我們還將用一個基于它用法最常見場景的示例來測試代碼:一個能夠在任何時間點開始播放視頻文件的HTML5頁面.

介紹

在本文中,我會闡述HTTP狀態206 分部分內容 的基礎概念,并使用Node.js一步步地實現它. 我們還將用一個基于它用法最常見場景的示例來測試代碼:一個能夠在任何時間點開始播放視頻文件的HTML5頁面. 

Partial Content 的簡要介紹

HTTP 的 206 Partial Content 狀態碼和其相關的消息頭提供了讓瀏覽器以及其他用戶代理從服務器接收部分內容而不是全部內容,這樣一種機制. 這一機制被廣泛使用在一個被大多數瀏覽器和諸如Windows Media Player和VLC Player這樣的播放器所支持視頻文件的傳輸上.

基礎的流程可以用下面這幾步描述:

  1. 瀏覽器請求內容.

  2. 服務器告訴瀏覽器,該內容可以使用 Accept-Ranges 消息頭進行分部分請求.

  3. 瀏覽器重新發送請求,用 Range 消息頭告訴服務器需要的內容范圍.

  4. 服務器會分如下兩種情況響應瀏覽器的請求: 

    • 如果范圍是合理的,服務器會返回所請求的部分內容,并帶上 206 Partial Content 狀態碼. 當前內容的范圍會在 Content-Range 消息頭中申明.

    • 如果范圍是不可用的(例如,比內容的總字節數大), 服務器會返回 416 請求范圍不合理 Requested Range Not Satisfiable 狀態碼. 可用的范圍也會在 Content-Range 消息頭中聲明.

讓我們來看看這幾個步驟中的每一個關鍵消息頭.

Accept-Ranges: 字節(bytes)

這是會有服務器發送的字節頭,展示可以被分部分發送給瀏覽器的內容. 這個值聲明了可被接受的每一個范圍請求, 大多數情況下是字節數 bytes

Range: 字節數(bytes)=(開始)-(結束)

這是瀏覽器告知服務器所需分部分內容范圍的消息頭. 注意開始和結束位置是都包括在內的,而且是從0開始的. 這個消息頭也可以不發送兩個位置,其含義如下: 

  • 如果結束位置被去掉了,服務器會返回從聲明的開始位置到整個內容的結束位置內容的最后一個可用字節.

  • 如果開始位置被去掉了,結束位置參數可以被描述成從最后一個可用的字節算起可以被服務器返回的字節數.

Content-Range:字節數(bytes)=(開始)-(結束)/(總數)

這個消息頭將會跟隨 HTTP 狀態碼 206 一起出現. 開始和結束的值展示了當前內容的范圍. 跟 Range 消息頭一樣, 兩個值都是包含在內的,并且也是從零開始的. 總數這個值聲明了可用字節的總數.

Content-Range: */(總數)

這個頭信息和上面一個是一樣的,不過是用另一種格式,并且僅在返回HTTP狀態碼416時被發送。其中總數代表了正文總共可用的字節數。

這里有一對有2048個字節文件的例子。注意省略起點和重點的區別。

請求開始的1024個字節

瀏覽器發送:

  1. GET /dota2/techies.mp4 HTTP/1.1  
  2. Host: localhost:8000  
  3. Range: bytes=0-1023 

服務器返回:

  1. HTTP/1.1 216 Partial Content  
  2. Date: Mon, 15 Sep 2014 22:19:34 GMT  
  3. Content-Type: video/mp4  
  4. Content-Range: bytes 0-1023/2048  
  5. Content-Length: 1024  
  6.    
  7. (Content...) 

沒有終點位置的請求

瀏覽器發送:

  1. GET /dota2/techies.mp4 HTTP/1.1  
  2. Host: localhost:8000  
  3. Range: bytes=1024

服務器返回:

  1. HTTP/1.1 216 Partial Content  
  2. Date: Mon, 15 Sep 2014 22:19:34 GMT  
  3. Content-Type: video/mp4  
  4. Content-Range: bytes 1024-2047/2048  
  5. Content-Length: 1024  
  6.    
  7. (Content...) 

注意:服務器并不需要在單個響應中返回所有剩下的字節,特別是當正文太長或者有其他性能的考慮。所以下面的兩個例子在這種情況下也是可接受的:

  1. Content-Range: bytes 1024-1535/2048  
  2. Content-Length: 512 

服務器僅返回剩余正文的一半。下一次請求的范圍將從第1536個字節開始。

  1. Content-Range: bytes 1024-1279/2048  
  2. Content-Length: 256 

服務器僅返回剩余正文的256個字節。下一次請求的范圍將從第1280個字節開始。

 

服務器返回:

  1. HTTP/1.1 216 Partial Content  
  2. Date: Mon, 15 Sep 2014 22:19:34 GMT  
  3. Content-Type: video/mp4  
  4. Content-Range: bytes 1536-2047/2048  
  5. Content-Length: 512  
  6.    
  7. (Content...) 

請求不可用的范圍:

瀏覽器發送:

  1. GET /dota2/techies.mp4 HTTP/1.1  
  2. Host: localhost:8000  
  3. Range: bytes=1024-4096 

服務器返回:

  1. HTTP/1.1 416 Requested Range Not Satisfiable  
  2. Date: Mon, 15 Sep 2014 22:19:34 GMT  
  3. Content-Range: bytes */2048 

理解了工作流和頭部信息后,現在我們可以用Node.js去實現這個機制。

#p#

第一步:創建一個簡單的HTTP服務器

我們將像下面的例子那樣,從一個基本的HTTP服務器開始。這已經可以基本足夠處理大多數的瀏覽器請求了。首先,我們初始化我們需要用到的對象,并且用initFolder來代表文件的位置。為了生成Content-Type頭部,我們列出文件擴展名和它們相對應的MIME名稱來構成一個字典。在回調函數httpListener()中,我們將僅允許GET可用。如果出現其他方法,服務器將返回405 Method Not Allowed,在文件不存在于initFolder,服務器將返回404 Not Found。

  1. // 初始化需要的對象  
  2. var http = require("http");  
  3. var fs = require("fs");  
  4. var path = require("path");  
  5. var url = require("url");  
  6.    
  7. // 初始的目錄,隨時可以改成你希望的目錄  
  8. var initFolder = "C:\\Users\\User\\Videos";  
  9.    
  10. // 將我們需要的文件擴展名和MIME名稱列出一個字典  
  11. var mimeNames = {  
  12.     ".css""text/css",  
  13.     ".html""text/html",  
  14.     ".js""application/javascript",  
  15.     ".mp3""audio/mpeg",  
  16.     ".mp4""video/mp4",  
  17.     ".ogg""application/ogg",   
  18.     ".ogv""video/ogg",   
  19.     ".oga""audio/ogg",  
  20.     ".txt""text/plain",  
  21.     ".wav""audio/x-wav",  
  22.     ".webm""video/webm";  
  23. };  
  24.    
  25. http.createServer(httpListener).listen(8000);  
  26.    
  27. function httpListener (request, response) {  
  28.     // 我們將只接受GET請求,否則返回405 'Method Not Allowed'  
  29.     if (request.method != "GET") {   
  30.         sendResponse(response, 405, {"Allow" : "GET"}, null);  
  31.         return null;  
  32.     }  
  33.    
  34.     var filename =   
  35.         initFolder + url.parse(request.url, truetrue).pathname.split('/').join(path.sep);  
  36.    
  37.     var responseHeaders = {};  
  38.     var stat = fs.statSync(filename);  
  39.     // 檢查文件是否存在,不存在就返回404 Not Found  
  40.     if (!fs.existsSync(filename)) {  
  41.         sendResponse(response, 404, nullnull);  
  42.         return null;  
  43.     }  
  44.     responseHeaders["Content-Type"] = getMimeNameFromExt(path.extname(filename));  
  45.     responseHeaders["Content-Length"] = stat.size; // 文件大小  
  46.            
  47.     sendResponse(response, 200, responseHeaders, fs.createReadStream(filename));  
  48. }  
  49.    
  50. function sendResponse(response, responseStatus, responseHeaders, readable) {  
  51.     response.writeHead(responseStatus, responseHeaders);  
  52.    
  53.     if (readable == null)  
  54.         response.end();  
  55.     else 
  56.         readable.on("open"function () {  
  57.             readable.pipe(response);  
  58.         });  
  59.    
  60.     return null;  
  61. }  
  62.    
  63. function getMimeNameFromExt(ext) {  
  64.     var result = mimeNames[ext.toLowerCase()];  
  65.        
  66.     // 最好給一個默認值  
  67.     if (result == null)  
  68.         result = "application/octet-stream";  
  69.        
  70.     return result;  

 

步驟 2 - 使用正則表達式捕獲Range消息頭

有了這個HTTP服務器做基礎,我們現在就可以用如下代碼處理Range消息頭了. 我們使用正則表達式將消息頭分割,以獲取開始和結束字符串。然后使用 parseInt() 方法將它們轉換成整形數. 如果返回值是 NaN (非數字not a number), 那么這個字符串就是沒有在這個消息頭中的. 參數totalLength展示了當前文件的總字節數. 我們將使用它計算開始和結束位置. 

  1. function readRangeHeader(range, totalLength) {  
  2.         /*  
  3.          * Example of the method 'split' with regular expression.  
  4.          *   
  5.          * Input: bytes=100-200  
  6.          * Output: [null, 100, 200, null]  
  7.          *   
  8.          * Input: bytes=-200  
  9.          * Output: [null, null, 200, null]  
  10.          */ 
  11.    
  12.     if (range == null || range.length == 0)  
  13.         return null;  
  14.    
  15.     var array = range.split(/bytes=([0-9]*)-([0-9]*)/);  
  16.     var start = parseInt(array[1]);  
  17.     var end = parseInt(array[2]);  
  18.     var result = {  
  19.         Start: isNaN(start) ? 0 : start,  
  20.         End: isNaN(end) ? (totalLength - 1) : end  
  21.     };  
  22.        
  23.     if (!isNaN(start) && isNaN(end)) {  
  24.         result.Start = start;  
  25.         result.End = totalLength - 1;  
  26.     }  
  27.    
  28.     if (isNaN(start) && !isNaN(end)) {  
  29.         result.Start = totalLength - end;  
  30.         result.End = totalLength - 1;  
  31.     }  
  32.    
  33.     return result;  

步驟 3 - 檢查數據范圍是否合理

回到函數 httpListener(), 在HTTP方法通過之后,現在我們來檢查請求的數據范圍是否可用. 如果瀏覽器沒有發送 Range 消息頭過來, 請求就會直接被當做一般的請求對待. 服務器會返回整個文件,HTTP狀態將會是 200 OK. 另外我們還會看看開始和結束位置是否比文件長度更大或者相等. 只要有一個是這種情況,請求的數據范圍就是不能被滿足的. 返回的狀態就將會是 416 Requested Range Not Satisfiable 而 Content-Range 也會被發送. 

  1. var responseHeaders = {};  
  2.     var stat = fs.statSync(filename);  
  3.     var rangeRequest = readRangeHeader(request.headers['range'], stat.size);  
  4.       
  5.     // If 'Range' header exists, we will parse it with Regular Expression.  
  6.     if (rangeRequest == null) {  
  7.         responseHeaders['Content-Type'] = getMimeNameFromExt(path.extname(filename));  
  8.         responseHeaders['Content-Length'] = stat.size;  // File size.  
  9.         responseHeaders['Accept-Ranges'] = 'bytes';  
  10.            
  11.         //  If not, will return file directly.  
  12.         sendResponse(response, 200, responseHeaders, fs.createReadStream(filename));  
  13.         return null;  
  14.     }  
  15.    
  16.     var start = rangeRequest.Start;  
  17.     var end = rangeRequest.End;  
  18.    
  19.     // If the range can't be fulfilled.   
  20.     if (start >= stat.size || end >= stat.size) {  
  21.         // Indicate the acceptable range.  
  22.         responseHeaders['Content-Range'] = 'bytes */' + stat.size; // File size.  
  23.    
  24.         // Return the 416 'Requested Range Not Satisfiable'.  
  25.         sendResponse(response, 416, responseHeaders, null);  
  26.         return null;  
  27.     } 

步驟 4 - 滿足請求

最后使人迷惑的一塊來了。對于狀態 216 Partial Content, 我們有另外一種格式的 Content-Range 消息頭,包括開始,結束位置以及當前文件的總字節數. 我們也還有 Content-Length 消息頭,其值就等于開始和結束位置之間的差。在最后一句代碼中,我們調用了 createReadStream() 并將開始和結束位置的值給了第二個參數選項的對象, 這意味著返回的流將只包含從開始到結束位置的只讀數據.

  1. // Indicate the current range.   
  2.     responseHeaders['Content-Range'] = 'bytes ' + start + '-' + end + '/' + stat.size;  
  3.     responseHeaders['Content-Length'] = start == end ? 0 : (end - start + 1);  
  4.     responseHeaders['Content-Type'] = getMimeNameFromExt(path.extname(filename));  
  5.     responseHeaders['Accept-Ranges'] = 'bytes';  
  6.     responseHeaders['Cache-Control'] = 'no-cache';  
  7.    
  8.     // Return the 206 'Partial Content'.  
  9.     sendResponse(response, 206,   
  10.         responseHeaders, fs.createReadStream(filename, { start: start, end: end })); 

下面是完整的 httpListener() 回調函數.

  1. function httpListener(request, response) {  
  2.     // We will only accept 'GET' method. Otherwise will return 405 'Method Not Allowed'.  
  3.     if (request.method != 'GET') {  
  4.         sendResponse(response, 405, { 'Allow''GET' }, null);  
  5.         return null;  
  6.     }  
  7.    
  8.     var filename =  
  9.         initFolder + url.parse(request.url, truetrue).pathname.split('/').join(path.sep);  
  10.    
  11.     // Check if file exists. If not, will return the 404 'Not Found'.   
  12.     if (!fs.existsSync(filename)) {  
  13.         sendResponse(response, 404, nullnull);  
  14.         return null;  
  15.     }  
  16.    
  17.     var responseHeaders = {};  
  18.     var stat = fs.statSync(filename);  
  19.     var rangeRequest = readRangeHeader(request.headers['range'], stat.size);  
  20.    
  21.     // If 'Range' header exists, we will parse it with Regular Expression.  
  22.     if (rangeRequest == null) {  
  23.         responseHeaders['Content-Type'] = getMimeNameFromExt(path.extname(filename));  
  24.         responseHeaders['Content-Length'] = stat.size;  // File size.  
  25.         responseHeaders['Accept-Ranges'] = 'bytes';  
  26.    
  27.         //  If not, will return file directly.  
  28.         sendResponse(response, 200, responseHeaders, fs.createReadStream(filename));  
  29.         return null;  
  30.     }  
  31.    
  32.     var start = rangeRequest.Start;  
  33.     var end = rangeRequest.End;  
  34.    
  35.     // If the range can't be fulfilled.   
  36.     if (start >= stat.size || end >= stat.size) {  
  37.         // Indicate the acceptable range.  
  38.         responseHeaders['Content-Range'] = 'bytes */' + stat.size; // File size.  
  39.    
  40.         // Return the 416 'Requested Range Not Satisfiable'.  
  41.         sendResponse(response, 416, responseHeaders, null);  
  42.         return null;  
  43.     }  
  44.    
  45.     // Indicate the current range.   
  46.     responseHeaders['Content-Range'] = 'bytes ' + start + '-' + end + '/' + stat.size;  
  47.     responseHeaders['Content-Length'] = start == end ? 0 : (end - start + 1);  
  48.     responseHeaders['Content-Type'] = getMimeNameFromExt(path.extname(filename));  
  49.     responseHeaders['Accept-Ranges'] = 'bytes';  
  50.     responseHeaders['Cache-Control'] = 'no-cache';  
  51.    
  52.     // Return the 206 'Partial Content'.  
  53.     sendResponse(response, 206,   
  54.         responseHeaders, fs.createReadStream(filename, { start: start, end: end }));  

#p#

測試實現

我們怎么來測試我們的代碼呢?就像在介紹中提到的,部分正文最常用的場景是流和播放視頻。所以我們創建了一個ID為mainPlayer并包含一個<source/>標簽的<video/>。函數onLoad()將在mainPlayer預讀取當前視頻的元數據時被觸發,這用于檢查在URL中是否有數字參數,如果有,mainPlayer將跳到指定的時間點。

  1. <!DOCTYPE html> 
  2. <html> 
  3.     <head> 
  4.         <script type="text/javascript"> 
  5.    
  6.             function onLoad() {  
  7.                 var sec = parseInt(document.location.search.substr(1));  
  8.                    
  9.                 if (!isNaN(sec))  
  10.                     mainPlayer.currentTime = sec;  
  11.             }  
  12.            
  13.         </script> 
  14.         <title>Partial Content Demonstration</title> 
  15.     </head> 
  16.     <body> 
  17.         <h3>Partial Content Demonstration</h3> 
  18.         <hr /> 
  19.         <video id="mainPlayer" width="640" height="360"   
  20.             autoplay="autoplay" controls="controls" onloadedmetadata="onLoad()"> 
  21.             <source src="dota2/techies.mp4" /> 
  22.         </video> 
  23.     </body> 
  24. </html> 

現在我們把頁面保存為"player.html"并和"dota2/techies.mp4"一起放在initFolder目錄下。然后在瀏覽器中打開URL:http://localhost:8000/player.html

在Chrome中看起來像這樣:

因為在URL中沒有任何參數,文件將從最開始出播放。

接下來就是有趣的部分了。讓我們試著打開這個然后看看發生了什么:http://localhost:8000/player.html?60

如果你按F12來打開Chrome的開發者工具,切換到網絡標簽頁,然后點擊查看最近一次日志的詳細信息。你會發現范圍的頭信息(Range)被你的瀏覽器發送了:

  1. Range:bytes=225084502

很有趣,對吧?當函數onLoad()改變currentTime屬性的時候,瀏覽器計算這部視頻60秒處的字節位置。因為mainPlayer已經預加載了元數據,包括格式、比特率和其他基本信息,這個起始位置立刻就被得到了。之后,瀏覽器就可以下載并播放視頻而不需要請求開頭的60秒了。成功了!

我們已經用Node.js來實現支持部分正文的HTTP服務器端了。我們也用HTML5頁面測試了。但這只是一個開始。如果你對頭部信息和工作流這些都已經理解透徹了,你可以試著用其他像ASP.NET MVC或者WCF服務這類框架來實現它。但是不要忘記啟動任務管理器來查看CPU和內存的使用。像我們在之前討論到的,服務器沒有在單個響應中返回所用剩余的字節。要找到性能的平衡點將是一項重要的任務。

英文原文:HTTP 206 Partial Content In Node.js

 

譯文出自:http://www.oschina.net/translate/http-partial-content-in-node-js

結論

開始用Node.js實現

請求最后512個字節

瀏覽器發送:

  1. GET /dota2/techies.mp4 HTTP/1.1  
  2. Host: localhost:8000  
  3. Range: bytes=-512 
責任編輯:林師授 來源: 開源中國社區 編譯
相關推薦

2017-04-24 08:31:26

Node.jsExpress.jsHTTP

2025-10-15 00:26:20

2011-09-08 14:16:12

Node.js

2023-06-30 23:25:46

HTTP模塊內存

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2013-11-01 09:34:56

Node.js技術

2017-03-20 13:43:51

Node.js內存泄漏

2017-03-19 16:40:28

漏洞Node.js內存泄漏

2021-10-03 15:02:50

HTTPNodejs

2017-08-17 13:56:30

JavascriptNode.jsHttp

2021-03-09 08:03:21

Node.js 線程JavaScript

2021-07-16 04:56:03

NodejsAddon

2012-10-24 14:56:30

IBMdw

2011-11-10 08:55:00

Node.js

2011-11-01 10:30:36

Node.js

2011-09-08 13:46:14

node.js

2011-09-09 14:23:13

Node.js

2011-09-02 14:47:48

Node

2024-01-05 08:49:15

Node.js異步編程

2020-04-15 15:48:03

Node.jsstream前端
點贊
收藏

51CTO技術棧公眾號

日本欧美一区二区三区不卡视频| 中文精品一区二区三区| 日韩 欧美 亚洲| 窝窝社区一区二区| 91久久精品网| 一区二区三区在线观看www| av资源免费看| 先锋a资源在线看亚洲| 中文字幕免费精品一区| 极品人妻一区二区| 成人爱爱网址| 亚洲免费资源在线播放| 精品国产一区二区三区日日嗨| 色老头一区二区| 欧美日韩精品一本二本三本 | 久久久久久久中文| av在线电影播放| 国产老女人精品毛片久久| 午夜精品福利视频| 欧美视频www| 欧美三级美国一级| 亚洲国产精品久久久久秋霞不卡 | 亚洲欧洲一区二区在线观看| 精品国产乱码一区二区三| 天堂一区二区在线| 久久人91精品久久久久久不卡| 亚洲一级黄色录像| 日韩影视高清在线观看| 日韩欧美二区三区| 国产又大又黄又猛| 免费成人直播| 黄色91在线观看| 日韩免费在线观看av| 在线免费看av| 国产日韩精品一区二区三区| 国产美女在线精品免费观看| 精品国产亚洲av麻豆| 久久er精品视频| 国产精品黄色av| 在线观看日本视频| 亚洲九九精品| 久久久影视精品| 久草网在线观看| 91精品国产自产拍在线观看蜜| 亚洲一级免费视频| 黄瓜视频污在线观看| 国产厕拍一区| 日韩精品一区二区三区视频在线观看| 久久人人爽av| 农村妇女一区二区| 欧美日韩在线三级| 免费一级特黄录像| 主播大秀视频在线观看一区二区| 色婷婷综合久久久中文一区二区| 国产老熟妇精品观看| 2021天堂中文幕一二区在线观| 一区二区三区精品在线| 50度灰在线观看| 欧美日韩经典丝袜| 亚洲国产综合91精品麻豆 | 亚洲尤物精选| 欧美亚洲第一页| 性无码专区无码| 久久精品九九| 国产精品网站入口| 91免费视频播放| 国产精品99久久不卡二区| 99re国产| 蜜桃视频污在线观看| av一区二区三区四区| 久久精精品视频| 久香视频在线观看| 国产精品国产自产拍高清av| 国产又爽又黄ai换脸| av激情在线| 五月天一区二区| 欧美黄色一级片视频| 91在线成人| 日韩午夜精品视频| 亚洲男人在线天堂| 精品一区二区三| 久久亚洲国产成人| 精品一区二区三区人妻| 香蕉久久a毛片| 国产欧美精品一区二区| 亚洲第一黄色片| 91浏览器在线视频| 亚洲一区三区| 超碰91在线观看| 91成人免费网站| 一区二区三区人妻| 亚洲精品推荐| 欧美插天视频在线播放| 亚洲伊人成人网| 精东粉嫩av免费一区二区三区| 国产富婆一区二区三区| 国产高清免费在线播放| 伊人性伊人情综合网| 国产成人亚洲精品无码h在线| 欧美爱爱视频| 亚洲精品一区二区网址| 久久av红桃一区二区禁漫| 1024日韩| 91久久久亚洲精品| 亚洲 小说区 图片区 都市| 国产精品国产a| 波多野结衣家庭教师在线播放| 欧美xxxx性| 亚洲欧美日韩爽爽影院| 九九视频免费看| 久久99日本精品| 久久亚洲高清| 欧美bbbxxxxx| 欧美精品自拍偷拍| 美女爆乳18禁www久久久久久| 欧美xxx在线观看| 国产精品91一区| 亚洲av成人无码久久精品老人 | 久久久久亚洲av成人毛片韩| 免费成人美女在线观看.| 国产精品一区二区三区免费| 最近高清中文在线字幕在线观看| 婷婷久久综合九色综合绿巨人| 小早川怜子一区二区三区| 国产免费久久| 5278欧美一区二区三区| 国精产品一品二品国精品69xx| 最新久久zyz资源站| 人妻无码视频一区二区三区| 久久影视三级福利片| 久久91亚洲精品中文字幕奶水| 中文字幕在线日亚洲9| 91丝袜美腿高跟国产极品老师 | 亚洲一区欧美在线| 国产成人在线色| 手机福利在线视频| 狠狠久久伊人中文字幕| 精品亚洲永久免费精品 | 欧美亚洲综合一区| 日本激情小视频| 亚洲欧美高清| 免费成人av网站| xx欧美视频| 亚洲男人天堂2019| 亚洲免费在线视频观看| 91天堂素人约啪| 116极品美女午夜一级| 久久久久久毛片免费看| 午夜精品久久久久久久99热| 日本精品久久久久| 精品久久久视频| 欧美大片免费播放器| 性久久久久久| 欧美日韩视频在线一区二区观看视频| 亚洲精品动漫| 国产性猛交xxxx免费看久久| 男操女视频网站| 久久精品免费在线观看| www.欧美日本| 欧美黄色大片在线观看| 92看片淫黄大片欧美看国产片 | 久久精品欧美一区| 亚洲www在线| 波多野结衣中文字幕久久| 亚洲国产一区自拍| 伊人手机在线视频| 国产视频一区二区在线观看| 日韩中文字幕a| 欧美精品一线| 久久久综合亚洲91久久98| 日韩精品免费观看视频| 日韩中文字幕在线视频播放| 99在线无码精品入口| 亚洲国产精品尤物yw在线观看| 亚洲成人av免费在线观看| 日韩av网站在线观看| 在线精品日韩| 豆花视频一区二区| 日本电影亚洲天堂| 麻豆免费在线观看| 亚洲精品一区二区三区精华液 | 欧美视频1区| 四虎国产精品成人免费影视| 久久91亚洲人成电影网站| 日韩成人黄色| 91精品国产麻豆国产自产在线| 精品肉丝脚一区二区三区| 久久精品夜色噜噜亚洲a∨ | 97久久久精品综合88久久| 不卡av免费在线| 亚洲自拍偷拍网| 久久综合九色综合久99| 亚洲伦理久久| 7777kkkk成人观看| 免费网站成人| 亚洲精品久久久久久下一站| 中文字幕自拍偷拍| 亚洲国产精品久久久男人的天堂| 亚洲黄色免费视频| 成人性生交大片免费看视频在线 | 51vv免费精品视频一区二区| 欧洲永久精品大片ww免费漫画| 日本视频在线播放| 日韩国产欧美区| 国产免费黄色网址| 色综合久久66| 国产无遮挡裸体免费视频| 国产精品色婷婷| 双性尿奴穿贞c带憋尿| 国内精品伊人久久久久av影院| 欧美日本视频在线观看| 天天色综合色| 日韩国产欧美一区| 美女主播精品视频一二三四| 成人午夜高潮视频| 欧美大片免费高清观看| 久久久爽爽爽美女图片| av电影高清在线观看| 日韩中文在线中文网在线观看| 亚洲 欧美 自拍偷拍| 欧美成人高清电影在线| 91成品人影院| 欧美在线不卡一区| 圆产精品久久久久久久久久久| 亚洲精品中文字幕乱码三区| 美女av免费看| 中国色在线观看另类| 亚洲最大成人网站| 99riav久久精品riav| 日本一区二区免费视频| 国产黑丝在线一区二区三区| 污色网站在线观看| 日韩**一区毛片| 国产精品亚洲a| 欧美在线综合| heyzo国产| 亚洲欧美大片| 欧美两根一起进3p做受视频| 免费日韩精品中文字幕视频在线| 91九色丨porny丨国产jk| 欧美日韩国产探花| 成年人深夜视频| 国产一区美女| 男人添女人荫蒂免费视频| 国产精品videosex极品| 奇米777四色影视在线看| 正在播放日韩欧美一页| 神马午夜伦理影院| 欧美在线影院| 日韩黄色短视频| 亚洲三级毛片| 东京热加勒比无码少妇| 美女视频一区免费观看| 欧美在线观看视频网站| 人人狠狠综合久久亚洲| 最新天堂在线视频| 国产毛片一区二区| 无套白嫩进入乌克兰美女| 国产成人免费视频网站高清观看视频| 91精品人妻一区二区三区蜜桃2 | 日韩精品三区四区| 五月婷婷六月丁香激情| 国内不卡的二区三区中文字幕| 免费欧美一级片| 成人免费福利片| 亚洲 小说 欧美 激情 另类| 国产精品你懂的在线| 精品国产视频一区二区三区| 亚洲国产一区二区三区青草影视| 日韩三级视频在线| 欧洲激情一区二区| 国产精品视频在线观看免费| 精品国产1区2区3区| 视频福利在线| 综合欧美国产视频二区| 91精选在线| 欧美亚洲激情视频| 日本a人精品| 国产精品国色综合久久| 国产欧美日韩| 国产女主播av| 蜜桃视频一区| 下面一进一出好爽视频| 97se亚洲国产综合自在线观| 国产午夜精品福利视频| 亚洲综合一二区| 成人a v视频| 欧美一级艳片视频免费观看| 视频三区在线观看| 久热99视频在线观看| 擼擼色在线看观看免费| 国产一区视频在线播放| 91在线一区| 日韩少妇中文字幕| 激情视频一区| 日本超碰在线观看| www.欧美色图| 国产日产精品一区二区三区的介绍| 亚洲电影一区二区三区| 亚洲系列第一页| 亚洲精品二三区| 国产成人午夜| 国产精品精品久久久| 久久99国产精品久久99大师 | 国产精品一区二区三区免费| 97精品在线| 91视频最新入口| 国产成a人无v码亚洲福利| 无码人妻丰满熟妇啪啪欧美| 亚洲国产一区在线观看| 国产精品久久影视| 亚洲小视频在线观看| av电影在线免费| 成人中心免费视频| 日韩国产专区| 精品视频一区二区在线| 成人h动漫精品一区二区| 神马久久精品综合| 在线免费不卡视频| 天堂a中文在线| 97成人精品视频在线观看| 一区二区三区在线资源| 一区二区三区四区欧美| 三级欧美韩日大片在线看| 在线免费观看a级片| 亚洲综合激情网| a天堂在线观看视频| 久久久成人的性感天堂| 看片一区二区| 亚洲精品一品区二品区三品区| 久久男女视频| 91中文字幕永久在线| 欧美日韩美女视频| 色窝窝无码一区二区三区| 欧美国产在线视频| 日韩一区二区三区精品| 免费观看黄色的网站| 久久99国内精品| 国产喷水在线观看| 欧美日本国产一区| 日本高清视频在线播放| 国产精品一二三在线| 清纯唯美综合亚洲| 91欧美视频在线| 成人欧美一区二区三区1314| 一二区在线观看| 久久av中文字幕| 日韩av综合| 国产精品国三级国产av| 成人午夜伦理影院| 国产在线拍揄自揄拍| 精品国产3级a| 黑人巨大亚洲一区二区久 | 国产福利在线看| 国产精品久久久久免费a∨ | 欧美成人免费全部| 亚洲欧美日本国产| 人妻夜夜添夜夜无码av| 久久午夜国产精品| 夜夜躁日日躁狠狠久久av| 中文字幕日韩有码| 中文字幕成人| www.九色.com| 91老师国产黑色丝袜在线| 在线永久看片免费的视频| 伊人久久久久久久久久久久久| 国产三级一区| 喜爱夜蒲2在线| 91日韩一区二区三区| 中国老头性行为xxxx| 久久久精品视频成人| 久草精品视频| 亚洲欧美自拍另类日韩| 一区二区三区四区在线播放| 婷婷在线观看视频| 国产91色在线| 伊人久久大香线蕉综合四虎小说| 91超薄肉色丝袜交足高跟凉鞋| 欧美午夜美女看片| 免费黄网在线观看| 国产午夜精品在线| 日韩电影免费在线观看网站| 欧美老熟妇一区二区三区| 亚洲精品成人久久久| 国外成人福利视频| 日本www在线视频| 国产精品免费视频一区| 欧美 日韩 国产 成人 在线 91| 日本欧美黄网站| 欧美a级片一区| 波多野在线播放| 日韩精品自拍偷拍| 精品免费av在线| 国产毛片久久久久久国产毛片| 国产色产综合产在线视频| www.爱爱.com| 国产精品成av人在线视午夜片| 欧美日韩国产高清| 精品一区二区6| 亚洲美女精品久久|