精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

自慰无码一区二区三区| 97人摸人人澡人人人超一碰| 亚洲精品国产一区黑色丝袜 | 久久久免费av| 国产精品第七页| 88xx成人网| 亚洲精品日韩一| 欧美精品一区在线| 国产精品老熟女视频一区二区| 亚洲国产日本| 色777狠狠综合秋免鲁丝| 日本wwww色| 日韩欧美2区| 亚洲五月六月丁香激情| 五月天亚洲综合情| 天天干天天做天天操| 久久精品99国产精品| 4444欧美成人kkkk| 久久精品99国产精| 日韩欧美一区二区三区在线视频| 亚洲精品电影网站| 亚洲国产综合av| 无人区在线高清完整免费版 一区二| 亚洲精品乱码久久久久久日本蜜臀| 久久久久久久久久久久久9999| 国产suv精品一区二区69| 日韩电影网1区2区| 热99在线视频| 亚洲欧美在线观看视频| 一二三区不卡| 最近2019好看的中文字幕免费 | 国产目拍亚洲精品99久久精品| 国产成人精品福利一区二区三区| 中文字幕+乱码+中文| 亚洲美女黄网| 欧美激情视频网站| 中文乱码字幕高清一区二区| 精品产国自在拍| 精品一区二区亚洲| youjizz.com日本| 欧美片网站免费| 91麻豆精品久久久久蜜臀| 91香蕉视频污版| 欧美成人性网| 一本到不卡精品视频在线观看| 亚洲 自拍 另类小说综合图区| 99在线播放| 中文字幕一区二区三区四区不卡 | 欧美中文字幕一区二区三区亚洲| 欧美日韩黄色一级片| av免费在线视| 亚洲第一综合色| 久久国产午夜精品理论片最新版本| 色婷婷视频在线观看| 亚洲男帅同性gay1069| 好色先生视频污| aa在线视频| 亚洲一二三四区不卡| 国产精品国产对白熟妇| 51精品视频| 精品久久久久久中文字幕大豆网| www插插插无码视频网站| 99在线视频影院| 午夜一区二区三区视频| heyzo亚洲| 在线成人av观看| 欧美日韩亚洲一区二| 国产精品第12页| 欧美影视资讯| 欧美剧情片在线观看| 国产精品嫩草影院8vv8 | 精品日韩美女| 国产综合在线观看| 国产精品美女久久久久久久久| 亚洲午夜久久久影院伊人| 免费高清在线观看| 一区二区三区中文免费| 国产素人在线观看| 99久久亚洲国产日韩美女| 欧美精品在欧美一区二区少妇| 免费黄频在线观看| www.亚洲一二| 亚洲深夜福利在线| 国产美女久久久久久| 国产精品vip| 日本高清久久天堂| 国产一区二区三区在线观看| 国产成人在线观看免费网站| 蜜桃欧美视频| 免费a级在线播放| 亚洲成国产人片在线观看| 欧美视频第一区| 亚洲我射av| 亚洲精品国产美女| а天堂中文在线资源| 悠悠资源网久久精品| 国产成人精品综合| av高清一区二区| 久久青草国产手机看片福利盒子| 一区二区精品在线| 3344国产永久在线观看视频| 欧美色精品天天在线观看视频| 一区二区在线免费观看视频| 国产精品一国产精品| 欧美日韩高清在线观看| 波多野结衣视频在线观看| 国产东北露脸精品视频| 欧美日韩一区二 | 亚洲日本护士毛茸茸| 3d动漫一区二区三区| 亚洲午夜国产成人| 亚洲精品资源美女情侣酒店| 欧美成人精品欧美一级| 日韩精品一卡二卡三卡四卡无卡| 国产精品久久久久久久久久久久冷| 岛国在线大片| 欧美日韩在线一区| 69久久精品无码一区二区| 精品国内自产拍在线观看视频 | 亚洲日本欧美中文幕| 少妇久久久久久被弄高潮| 日本麻豆一区二区三区视频| 蜜桃传媒视频麻豆第一区免费观看 | 亚洲人成五月天| 国产极品美女高潮无套嗷嗷叫酒店 | 一区精品在线播放| av视屏在线播放| 日韩欧美影院| 午夜精品蜜臀一区二区三区免费 | 精品国产一区二区三区久久久蜜月| 天天操天天舔天天射| 国产亚洲精品v| 国产激情美女久久久久久吹潮| 黄网页在线观看| 欧美中文字幕一区二区三区| 91成人破解版| 免费在线亚洲欧美| 国产丝袜不卡| www.九色在线| 亚洲第一二三四五区| 久久精品这里只有精品| 国产自产2019最新不卡| 一区国产精品| 亚洲成人高清| 久久亚洲一区二区三区四区五区高| 中文字幕日韩经典| 中文字幕不卡在线播放| 另类小说色综合| 波多野结衣在线观看一区二区 | 人妻中文字幕一区二区三区| 国产亚洲综合在线| 毛葺葺老太做受视频| 国产精品三级| 国产精品爽黄69天堂a| 69av在线| 欧美一二三在线| 欧美日韩精品一区二区三区视频播放| 国产精品白丝av| 成人在线免费观看网址| 18国产精品| 国内精品久久久久伊人av| 天堂在线一二区| 日韩欧美在线一区| 最近中文字幕免费| 奇米精品一区二区三区在线观看一| 日韩午夜视频在线观看| 日韩毛片一区| 久色乳综合思思在线视频| 精品国产伦一区二区三| 亚洲福中文字幕伊人影院| 韩国无码一区二区三区精品| 每日更新成人在线视频| 在线播放豆国产99亚洲| 日韩一区二区三区精品| 97精品在线视频| 国产永久免费高清在线观看视频| 欧美日韩国产美女| 久久精品国产亚洲AV无码男同 | 免费观看成人www动漫视频| 国内免费久久久久久久久久久| 无码国产精品96久久久久| 日韩欧美国产免费播放| 老司机精品免费视频| 国产成人小视频| 日本三级免费观看| 成人影院在线| av色综合网| 日韩在线影院| 久久99精品国产99久久6尤物| 亚洲av成人无码网天堂| 欧美私模裸体表演在线观看| 久久久久久久久久久久久久免费看| 96av麻豆蜜桃一区二区| 国产福利在线免费| 日韩一级网站| 亚洲综合第一| 欧美偷窥清纯综合图区| 国产欧美中文字幕| 日韩精品av| 久久精品国产一区| 精品福利视频导航大全| 日韩三级视频在线观看| 亚洲永久精品一区| 亚洲午夜久久久久久久久电影网 | 91精品国产高清自在线| jyzzz在线观看视频| 亚洲精品按摩视频| 国产免费不卡视频| 在线视频欧美精品| 日韩精品乱码久久久久久| 中文字幕在线一区二区三区| 日本丰满少妇裸体自慰| 国产福利不卡视频| 国产无遮挡猛进猛出免费软件 | 国产又爽又黄网站亚洲视频123| 欧美日韩免费一区二区三区| 日韩 欧美 中文| 亚洲精品福利视频网站| 精品国产aaa| www国产亚洲精品久久麻豆| 久久久久99人妻一区二区三区| 免费国产亚洲视频| 日韩中文字幕三区| 日韩视频在线一区二区三区 | 欧美本精品男人aⅴ天堂| 自拍偷拍第八页| 日韩欧美国产中文字幕| 国产午夜精品无码一区二区| 亚洲蜜桃精久久久久久久| 国产馆在线观看| 国产欧美一区二区三区在线看蜜臀| 人妻换人妻a片爽麻豆| 国产精品一色哟哟哟| 色一情一区二区三区| 蜜桃久久久久久久| 中文字幕第80页| 久久香蕉精品| 国产成人久久777777| 国产精品夜夜夜| 99精品人妻少妇一区二区 | 欧美一区电影| 日韩久久精品一区二区三区| 国产va免费精品观看精品视频| 蜜桃av久久久亚洲精品| 丝袜av一区| 免费国产一区| 精品国产91| 亚洲精品中字| 先锋资源久久| dy888午夜| 国精品一区二区| 97在线国产视频| 久久国产66| 久久黄色免费看| 美日韩一区二区| 天天干天天色天天干| 韩国精品在线观看| 久久久久亚洲av无码专区首jn| 国产aⅴ综合色| 日韩精品人妻中文字幕有码| 97久久人人超碰| 美女被到爽高潮视频| 国产精品三级视频| 国产尤物在线播放| 亚洲国产aⅴ天堂久久| 国产免费观看av| 欧美日韩一区中文字幕| 国产精品久久久久久免费免熟| 日韩一区二区在线看| 三级在线观看网站| 亚洲欧美国产高清va在线播| 北岛玲一区二区三区| 欧美成人在线免费视频| 国产白丝在线观看| 日韩美女视频免费在线观看| 日韩欧美激情| 国产伦精品一区二区三区免费视频| 秋霞影院一区二区三区| 色涩成人影视在线播放| 91精品91| 欧美亚洲国产成人| 久久爱www久久做| 一边摸一边做爽的视频17国产 | 老牛嫩草一区二区三区日本| 污网站在线免费| www.成人网.com| 内射毛片内射国产夫妻| 一区二区三区四区在线免费观看| 久久露脸国语精品国产91| 欧美在线观看视频在线| а√天堂资源在线| 亚洲欧洲国产一区| 日本小视频在线免费观看| 欧洲亚洲妇女av| 国产一区二区高清在线| 久久综合中文色婷婷| 一区二区蜜桃| 粉嫩虎白女毛片人体| 国产成人精品亚洲午夜麻豆| 久久成人激情视频| 亚洲一区二区三区不卡国产欧美| 精品黑人一区二区三区| 精品久久久久久久久久久久久久久久久 | 欧产日产国产69| 日韩欧美一级片| av在线播放av| 2018日韩中文字幕| 日本一区二区三区电影免费观看| 日本精品一区二区三区不卡无字幕| 欧美国产激情| 污色网站在线观看| 久久综合色综合88| 久久婷婷国产麻豆91| 7777精品伊人久久久大香线蕉完整版 | 中文字幕成在线观看| 69堂成人精品视频免费| 色偷偷综合网| 欧美激情成人网| 91免费小视频| 青青草av在线播放| 日韩一级成人av| av免费在线网站| 成人中文字幕在线观看| 欧美亚洲高清| 妺妺窝人体色www在线观看| 91丨porny丨国产| 久久精品国产亚洲av麻豆色欲| 欧美一区二区三区成人| 日韩理伦片在线| 国产精品嫩草影院一区二区| 亚洲理论电影| 国产精品宾馆在线精品酒店| 成人99免费视频| 国产一级片免费| 精品国产一区二区三区四区四| av毛片在线播放| 91黄在线观看| 欧美日本亚洲韩国国产| 香蕉视频xxx| 亚洲免费视频中文字幕| 国产三级午夜理伦三级| 久久在线精品视频| 国产成人久久精品麻豆二区| 色一情一乱一伦一区二区三欧美| 美女尤物久久精品| 亚洲成人黄色av| 欧美自拍偷拍午夜视频| www在线播放| 国产日韩精品入口| 99视频精品全部免费在线视频| 亚洲欧美自偷自拍另类| 中文字幕在线不卡视频| jizz中国少妇| 欧美黑人性生活视频| 国产精品调教| 久久婷婷五月综合色国产香蕉| 91色在线porny| 中文字幕免费高清网站| 原创国产精品91| 亚洲视频资源| cao在线观看| 2021国产精品久久精品| 国产一卡二卡三卡| 日韩在线免费高清视频| a一区二区三区亚洲| 屁屁影院ccyy国产第一页| 成人国产在线观看| 麻豆成人免费视频| 色偷偷偷综合中文字幕;dd| 精品精品视频| 免费观看美女裸体网站| 欧美极品美女视频| 99热这里只有精| 97视频在线免费观看| 欧美日韩亚洲在线观看| 黄色三级视频在线播放| 欧美日韩国产限制| 98在线视频| 成人av资源网| 久久综合婷婷| 亚洲熟女www一区二区三区| 亚洲精品白浆高清久久久久久| 一区二区视频免费完整版观看| 法国空姐在线观看免费| www.成人网.com| 一区二区三区亚洲视频| 97欧美精品一区二区三区| 成人高清电影网站| 亚洲精品久久一区二区三区777| 色综合天天综合网天天狠天天| 黄网址在线观看| 欧美成人免费在线| 国产精品综合网| 中文字幕日韩免费| 欧美成人高清视频| 欧美日韩激情在线一区二区三区| 九九九久久久久久久| 在线一区二区三区四区| 神马午夜伦理不卡| 亚洲国产午夜伦理片大全在线观看网站|