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

前端領域如何實現請求中斷

開發 前端
本文主要是基于目前前端領域使用的幾種比較常見的網絡請求方案,講解了一下在代碼層面各自實現請求中斷的處理方式。

幾乎在所有面向用戶或企業的應用程序中,所呈現出來的信息都不是一成不變的,即數據都是動態的,由某個或者多個后臺服務所提供。那么就不可避免地會涉及到網絡請求,而對于不同企業肯定有不同的業務場景。

在一個功能完善的應用程序呈現給用戶之前,前后端開發人員必須先根據產品經理提供的業務需求文檔協商建立起格式良好的接口契約,然后再經過開發聯調測試驗證部署上線等一系列流程之后才具有可用性,才能展現在用戶面前供用戶使用。

但是可能并不是在任何場景下,我們都需要關心網絡請求的響應結果,或者說在某些場景下,我們只需要關心最新的有效的網絡請求,對于老舊的失效的網絡請求,我們甚至可以忽略它的存在。

我們知道,從瀏覽器發起一次網絡請求,到建立TCP鏈接(對于HTTPS協議還需要建立額外的TLS連接)以及DNS域名解析,再到發送請求數據報文,最終服務器處理請求并響應數據,期間會不停占用客戶端和服務器資源。

如果該網絡請求對于我們而言已經無效,那么我們就可以通過手動中斷請求,來提前釋放被占用的資源,減少不必要的資源開銷。

例如考慮以下場景:

  • 在Vue或React單頁應用中,組件A掛載完畢之后向后臺服務發起請求拉取數據,但是由于加載過慢,用戶可能期間發生路由跳轉或回退,導致組件A卸載,但是組件內部的網絡請求并沒有立即停止下來,此時的響應數據對于已卸載的組件A而言已經無效。若剛好此時請求響應錯誤,就可能導致前端實現的兜底彈窗出現在跳轉后的頁面中,造成視覺干擾;
  • 頁面存在定時輪詢業務,即固定間隔一段時間再次發起請求,這樣就可能存在多個請求間的競爭關系,如果上一個請求的響應速度比最近一次請求的響應速度慢,則前者就會覆蓋后者,從而導致數據錯亂;
  • 類似于關鍵字搜索或模糊查詢等需要頻繁發起網絡請求的相關業務,可能在一定程度上為了優化程序的執行性能,減少冗余的網絡IO,我們會使用防抖(debounce)函數來對請求邏輯進行包裝,減少查詢次數以降低服務器壓力,但是依舊避免不了由于加載耗時過長導致新老請求數據錯亂的問題;
  • 針對前端大文件上傳等上傳服務,需要實現上傳進度的暫停與恢復,即斷點續傳。

還有很多其他沒有列出的應用場景,針對每種應用場景,雖然我們都能給出對應的方案來解決實際問題,但是筆者認為最理想的方案還是盡量減少無用請求,減少客戶端和服務器之間的無效傳輸,鑒于此也就引入了本文中將要講到的中斷請求的方式。

在前端領域,個人覺得有幾種比較常見的網絡請求方案:瀏覽器原生支持的XMLHttpRequest對象,同時兼容瀏覽器端和NodeJS服務端的第三方HTTP庫Axios和大部分瀏覽器最新實現的Fetch API。本文主要基于以上三種請求方案講解一下各自中斷請求的方式,文中若有錯誤,還請指正。

1、XMLHttpRequest

瀏覽器原生實現的XMLHttpRequest(以下簡稱XHR)構造函數對于我們來說已經是再熟悉不過了,但是在實際應用中,大部分場景下可能我們并不需要去主動實例化XHR構造函數,畢竟實例化之后還需要通過調用open和send等一系列的官方API才能實現與服務器的數據交互,操作細節稍微繁瑣。

相反我們一般會推薦使用社區實現的第三方庫來方便我們簡化操作流程,提升開發效率,例如下一節將要講述的Axios。但即便是Axios,在瀏覽器端其底層依舊是通過XHR構造函數來實現網絡IO的,因此這一小節有必要對XHR的相關知識點進行回顧和講解。

首先拋出一個基礎示例:

/**
* @description: 基于 XHR 封裝的網絡請求工具函數
* @param {String} url 請求接口地址
* @param {Document | XMLHttpRequestBodyInit | null} body 請求體
* @param {Object} requestHeader 請求頭
* @param {String} method 請求方法
* @param {String} responseType 設置響應內容的解析格式
* @param {Boolean} async 請求是否異步
* @param {Number} timeout 設置請求超時時間(單位:毫秒)
* @param {Boolean} withCredentials 設置跨域請求是否允許攜帶 cookies 或 Authorization header 等授權信息
* @return {Promise} 可包含響應內容的 Promise 實例
*/
function request({
url,
body = null,
requestHeader = {'Content-Type': 'application/x-www-form-urlencoded'},
method = 'GET',
responseType = 'text',
async = true,
timeout = 30000,
withCredentials = false,
} = {}) {
return new Promise((resolve, reject) => {
if (!url) {
return reject(new TypeError('the required parameter [url] is missing.'));
}
if (method.toLowerCase() === 'get' && body) {
url += `?${request.serialize(body)}`;
body = null;
}
const xhr = new XMLHttpRequest();
xhr.open(method, url, async);
if (async) {
xhr.responseType = responseType;
xhr.timeout = timeout;
}
xhr.withCredentials = withCredentials;
if (requestHeader && typeof requestHeader === 'object') {
Object.keys(requestHeader).forEach(key => xhr.setRequestHeader(key, requestHeader[key]));
}
xhr.onreadystatechange = function onReadyStateChange() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
resolve(xhr.response);
}
}
};
xhr.onerror = function onError(error) {
console.log(error);
reject({ message: '請求出錯,請稍后重試' });
};
xhr.ontimeout = function onTimeout() {
reject({ message: '接口超時,請稍后重試' });
};
xhr.send(body ? JSON.stringify(body) : null);
});
}

以上示例對XHR請求操作流程進行了一下簡單的封裝,并未涉及到太多的細節和兼容處理。一個簡單的調用方式如下:

request({
url: 'http://www.some-domain.com/path/to/example',
method: 'POST',
requestHeader: {'Content-Type': 'application/json; charset=UTF-8'},
body: {key: value}
}).then(response => console.log(response));

基于以上操作便完成了一次客戶端和服務器的數據交互請求,接下來在此基礎上繼續完善請求中斷的相關邏輯。

我們知道,在XHR實例上為我們提供了一個abort方法用于終止該請求,并且當一個請求被終止的時候,該請求所對應的XHR實例的readyState屬性將會被設置為XMLHttpRequest.UNSET(0),同時status屬性會被重置為0,因此在本示例中我們同樣使用abort方法來實現請求中斷。

// 參考以上示例
function request
// 省略入參
...
} = {}) {
return new Promise((resolve, reject) => {
// 省略代碼
...
});
}
// 存儲請求接口地址以及請求體和 XHR 實例的映射關系
request.cache = {};
/**
* @description: 根據提供的鍵名中斷對應的請求
* @param {String} key 存儲在 request.cache 屬性中的鍵名,若未提供則中斷全部請求
* @return {void}
*/
request.clearCache = (key) => {
if (key) {
const instance = request.cache[key];
if (instance) {
instance.abort();
delete request.cache[key];
}
return;
}
Object.keys(request.cache).forEach(cacheKey => {
const instance = request.cache[cacheKey];
instance.abort();
delete request.cache[cacheKey];
});
};

在以上示例中,我們通過request.cache來臨時存儲請求接口地址以及請求體和XHR實例的映射關系,因為在同一頁面中一般可能會涉及到多個接口地址不同的請求,或者同一個請求對應不同的請求體,因此這里考慮加上了請求體以做區分。當然為了作為request.cache中的唯一鍵名,我們還需要對請求體進行序列化操作,因此簡單封裝一個序列化工具函數。

/**
* @description: 將請求體序列化為字符串
* @param {Document | XMLHttpRequestBodyInit | null} data 請求體
* @return {String} 序列化后的字符串
*/
request.serialize = (data) => {
if (data && typeof data === 'object') {
const result = [];
Object.keys(data).forEach(key => {
result.push(`${key}=${JSON.stringify(data[key])}`);
});
return result.join('&');
}
return data;
}

完成以上的基礎代碼之后,接下來我們將其應用到request函數中:

function request({
url,
body = null,
// 省略部分入參
...
} = {}) {
return new Promise((resolve, reject) => {
if (!url) {
return reject(new TypeError('the required parameter [url] is missing.'));
}
// 省略部分代碼
...
const xhr = new XMLHttpRequest();
// 將請求接口地址以及請求體和 XHR 實例存入 cache 中
let cacheKey = url;
if (body) {
cacheKey += `_${request.serialize(body)}`;
}
// 每次發送請求之前將上一個未完成的相同請求進行中斷
request.cache[cacheKey] && request.clearCache(cacheKey);
request.cache[cacheKey] = xhr;
// 省略部分代碼
...
xhr.onreadystatechange = function onReadyStateChange() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
// 請求完成之后清除緩存
request.clearCache(cacheKey);
resolve(xhr.response);
}
}
};
xhr.onerror = function onError(error) {
console.log(error);
// 請求報錯之后清除緩存
request.clearCache(cacheKey);
reject({ message: '請求出錯,請稍后重試' });
};
xhr.ontimeout = function onTimeout() {
// 請求超時之后清除緩存
request.clearCache(cacheKey);
reject({ message: '接口超時,請稍后重試' });
};
xhr.send(body ? JSON.stringify(body) : null);
});
}

這樣便簡單實現了一個自包含的請求中斷的處理邏輯,每次發送請求之前自動判定未完成的多余請求并將其清除,從而避免性能上的開銷。

當然,不僅如此,這里同樣可以通過request.clearCache函數來在組件卸載或路由跳轉的時候手動清除未完成的請求,因為這部分請求對于卸載后的組件而言沒有太多實質意義,例如以下示例:

// 網頁卸載前清除緩存
window.addEventListener('beforeunload', () => request.clearCache(), false);
// Vue 中路由跳轉前清除緩存
router.beforeEach((to, from, next) => { request.clearCache(); next(); });
// React 中路由跳轉時清除緩存
import { Component } from 'react';
import { withRouter } from 'react-router-dom';
class App extends Component {
componentDidMount() {
// 監聽路由變化
this.props.history.listen(location => {
// 通過比較 location.pathname 來判定路由是否發生變化
if (this.props.location.pathname !== location.pathname) {
// 若路由發生變化,則清除緩存
request.clearCache();
}
});
}
}
export default withRouter(App);

2、Axios

Axios想必是我們使用最多的一個第三方開源免費的HTTP庫,其本身基于Promise的特性使得我們可以很方便地寫出更加優雅且易維護的代碼,從而避免函數多層嵌套所帶來的一系列問題。

當然,它最大的特點在于可以同時兼容瀏覽器端和NodeJS服務端。底層通過判定不同的運行環境來自動提供不同的適配器,在瀏覽器端通過原生的XHR對象來發送請求,而在NodeJS服務端則通過內置的http模塊來發送請求。

不僅如此,在其底層的Promise管道鏈中還為我們暴露了稱之為攔截器的入口,使得我們可以參與到一個請求的生命周期中,在請求發送之前和響應接收之后能夠自定義實現數據的裝配和轉換操作。帶來的如此之多的人性化操作,使得我們沒有理由不去用它,這也奠定了其長久以來依舊如此火爆的基礎。

言歸正傳,在Axios中同樣為我們提供了請求中斷的相關API。首先拋出一個基礎示例:

// 安裝 axios
npm install --save axios
// 導入 axios
import axios from 'axios';
// 創建 axios 實例
const instance = axios.create({
baseURL: 'https://www.some-domain.com/path/to/example',
timeout: 30000,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
// 設置 axios 實例默認配置
instance.defaults.headers.common['Authorization'] = '';
instance.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8';
// 自定義請求攔截器
instance.interceptors.request.use(config => {
const token = window.localStorage.getItem('token');
token && (config.headers['Authorization'] = token);
return config;
}, error => Promise.reject(error));
// 自定義響應攔截器
instance.interceptors.response.use(response => {
if (response.status === 200) {
return Promise.resolve(response.data);
}
return Promise.reject(response);
}, error => Promise.reject(error));

接下來我們結合Axios提供的CancelToken構造函數來創建一個簡單的post請求:

const CancelToken = axios.CancelToken;
let cancel;
instance.post('/api/user/123', {
name: 'new name',
phone: 'new phone',
}, {
// CancelToken 構造函數接收一個 executor 函數參數,并且該函數接收一個取消函數 c 用于取消該次請求
cancelToken: new CancelToken(function executor(c) {
// 將取消函數賦值到外部變量,方便從外部取消請求
cancel = c;
}),
});
// 手動取消請求
cancel();

針對需要同時取消多個請求以及自動取消的應用場景,上面的示例顯然不能滿足我們的需求。這里我們同樣可以利用上一小節的思路來維護一個請求接口地址以及請求體和取消函數c之間的映射關系。

同時為了避免在每個請求中都需要手動去實例化CancelToken,我們可以巧妙利用request攔截器來整合這部分的邏輯,實現邏輯復用。首先我們將緩存邏輯拆分到一個單獨的文件中:

// cacheUtils.js
export const CacheUtils = {
// 存儲請求接口地址以及請求體和取消函數之間的映射關系
cache: {},
// 根據提供的鍵名 key 取消對應的請求,若未提供則取消全部請求
clearCache: function (key) {
if (key) {
const cancel = this.cache[key];
if (cancel && typeof cancel === 'function') {
cancel();
delete this.cache[key];
}
return;
}
Object.keys(this.cache).forEach(cacheKey => {
const cancel = this.cache[cacheKey];
cancel();
delete this.cache[cacheKey];
});
},
};

接下來我們將其應用到請求攔截器和響應攔截器中:

import qs from 'qs';
import { CacheUtils } from './cacheUtils.js';
// 自定義請求攔截器
instance.interceptors.request.use(config => {
let cacheKey = config.url;
const token = window.localStorage.getItem('token');
token && (config.headers['Authorization'] = token);
const method = config.method.toLowerCase();
if (method === 'get' && config.params && typeof config.params === 'object') {
cacheKey += qs.stringify(config.params, { addQueryPrefix: true });
}
if (['post', 'put', 'patch'].includes(method) && config.data && typeof config.data === 'object') {
config.data = qs.stringify(config.data);
cacheKey += `_${qs.stringify(config.data, { arrayFormat: 'brackets' })}`;
}
// 每次發送請求之前將上一個未完成的相同請求進行中斷
CacheUtils.cache[cacheKey] && CacheUtils.clearCache(cacheKey);
// 將當前請求所對應的取消函數存入緩存
config.cancelToken = new axios.CancelToken(function executor(c) {
CacheUtils.cache[cacheKey] = c;
});
// 臨時保存 cacheKey,用于在響應攔截器中清除緩存
config.cacheKey = cacheKey;
return config;
}, error => Promise.reject(error));
// 自定義響應攔截器
instance.interceptors.response.use(response => {
// 響應接收之后清除緩存
const cacheKey = response.config.cacheKey;
delete CacheUtils.cache[cacheKey];
if (response.status === 200) {
return Promise.resolve(response.data);
}
return Promise.reject(response);
}, error => {
// 響應異常清除緩存
if (error.config) {
const cacheKey = error.config.cacheKey;
delete CacheUtils.cache[cacheKey];
}
return Promise.reject(error);
});

這里我們同樣提供CacheUtils.clearCache函數來應對需要手動清除未完成請求的應用場景,使用方式與上一小節思路相同,這里就不再重復多講。

3、Fetch API

作為瀏覽器原生提供的XHR構造函數的理想替代方案,新增的Fetch API為我們提供了Request和Response(以及其他與網絡請求有關的)對象的通用定義,一個Request對象表示一個資源請求,通常包含一些初始數據和正文內容,例如資源請求路徑、請求方式、請求主體等,而一個Response對象則表示對一次請求的響應數據。

同時Fetch API還為我們提供了一個全局的fetch方法,通過該方法我們可以更加簡單合理地跨網絡異步獲取資源。fetch方法不僅原生支持Promise的鏈式操作,同時還支持直接傳入Request對象來發送請求,增加了很強的靈活性。

到目前為止,Fetch API的支持程度如下圖:

不難看出IE瀏覽器下的兼容性不容樂觀,但是作為一名有追求的前端開發人員,當然不會止步于此。一番探索之后,發現可以通過isomorphic-fetch或者whatwg-fetch這兩個第三方依賴來解決兼容性問題:

// 安裝依賴
npm install --save whatwg-fetch
// 引入依賴
import {fetch as fetchPolyfill} from 'whatwg-fetch';

接下來同樣先拋出一個基礎示例:

const url = 'http://www.some-domain.com/path/to/example';
const initData = {
method: 'POST',
body: JSON.stringify({key: value}),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
cache: 'no-cache',
credentials: 'same-origin',
mode: 'cors',
redirect: 'follow',
referrer: 'no-referrer',
};
fetch(url, initData).then(response => response.json()).then(data => console.log(data));
// 也可以直接通過 Request 構造函數來初始化請求數據
// Request 構造函數接收兩個參數
// 第一個參數表示需要獲取的資源 URL 路徑或者另一個嵌套的 Request 實例
// 第二個可選參數表示需要被包含到請求中的各種自定義選項
const request = new Request(url, initData);
fetch(request).then(response => response.json()).then(data => console.log(data));

可以看到,相比于傳統的XHR方式而言,fetch函數的使用方式更加簡潔友好,易用性更強,同時還為我們提供了多種入參的形式使得程序功能變得更加的靈活可擴展。

那么回到本文的主題,上文中提到,在XHR實例中可以通過abort方法來取消請求,在Axios中可以通過CancelToken構造函數的參數來獲得取消函數,從而通過取消函數來取消請求。

但是很遺憾的是,在Fetch API中,并沒有自帶的取消請求的API供我們調用。不過令人愉悅的是,除了IE瀏覽器外,其他瀏覽器已經為Abort API添加了實驗性支持,Abort API允許對XHR和fetch這樣的請求操作在未完成時進行終止,那么接下來對Abort API做一下簡要的介紹。

在Abort API的相關概念中主要包含了AbortController和AbortSignal兩大接口:

  • AbortController:表示一個控制器對象,該對象擁有一個只讀屬性signal和一個方法abort。signal屬性表示一個AbortSignal實例,當我們需要取消某一個請求時,需要將該signal屬性所對應的AbortSignal實例與請求進行關聯,然后通過控制器對象提供的abort方法來取消請求;
  • AbortSignal:表示一個信號對象,作為控制器對象和請求之間通信的橋梁,允許我們通過控制器對象來對請求進行取消操作。該對象擁有一個只讀屬性aborted和一個方法onabort,aborted屬性體現為一個布爾值,表示與之通信的請求是否已經被終止,而onabort方法會在控制器對象終止該請求時調用。

通過以上兩個接口,我們嘗試封裝一個簡單加強版的可取消的fetch工具函數:

const abortableFetch = (url, initData) => {
// 實例化控制器對象
const abortController = new AbortController();
// 獲取信號對象
const signal = abortController.signal;
return {
// 注意這里需要將 signal 信號對象與請求進行關聯,關聯之后才能通過 abortController.abort 方法取消請求
ready: fetch(url, {...initData, signal}).then(response => response.json()),
// 暴露 cancel 方法,用于在外層手動取消請求
cancel: () => abortController.abort(),
};
};

并將其應用到之前的基礎示例中:

const url = 'http://www.some-domain.com/path/to/example';
const initData = {
method: 'POST',
body: JSON.stringify({key: value}),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
cache: 'no-cache',
credentials: 'same-origin',
mode: 'cors',
redirect: 'follow',
referrer: 'no-referrer',
};
const {ready, cancel} = abortableFetch(url, initData);
ready
.then(response => console.log(response))
.catch(err => {
if (err.name === 'AbortError') {
console.log('請求已被終止');
}
});
// 手動取消請求
cancel();

至此我們便成功完成了基于Abort API的請求中斷邏輯,當然如果針對需要同時取消多個請求以及自動取消的應用場景,在abortableFetch函數中我們已經對外暴露了cancel方法,是不是想起來在第二小節介紹Axios的過程中,同樣出現過cancel方法,  

所以這里完全可以借助上文中的思路,構建出請求路徑與請求體以及cancel取消函數之間的映射關系,對緩存進行集中管理并對外提供清空緩存的工具方法,由于實現思路與上文中的大同小異,這里就不再展開細講,感興趣的小伙伴兒可以自己嘗試下。

總結

這里我們再次回顧一下本文主要講解的內容,本文主要是基于目前前端領域使用的幾種比較常見的網絡請求方案,講解了一下在代碼層面各自實現請求中斷的處理方式。

在瀏覽器原生提供的XHR對象中,我們通過實例上的abort方法來終止請求。在Axios庫中,我們借助于其提供的CancelToken構造函數同樣實現了請求中斷。

最后,我們通過fetch函數和Abort API的相互配合,實現了在現代主流瀏覽器的Fetch API中請求中斷的方式。通過這些優化操作可以提前釋放被占用的資源,一定程度上減少了不必要的資源開銷。

責任編輯:龐桂玉 來源: 前端大全
相關推薦

2022-03-01 17:34:52

前端架構代碼

2024-03-29 09:00:51

前端數據后端

2024-08-26 08:47:32

2023-04-10 15:14:03

2021-04-22 05:37:14

Axios 開源項目HTTP 攔截器

2021-07-11 06:46:17

前端設計模式

2022-01-18 09:02:45

請求前端代碼

2024-07-26 08:53:09

前端參數后端

2024-08-05 09:29:00

前端接口請求

2024-04-23 14:02:42

CIO

2022-09-26 00:42:43

GuavaJDK動態代理

2019-12-04 11:00:42

前端DockerKubernetes

2022-11-23 10:22:12

組件庫前端

2022-11-24 16:11:27

2023-03-23 09:09:32

前端詞云效果

2025-07-15 09:08:36

2022-12-26 00:00:01

Go框架前端

2021-01-25 06:53:59

前端AJAX技術熱點

2022-12-01 17:46:53

網頁變灰功能前端

2025-01-14 10:09:43

硬中斷Linux系統
點贊
收藏

51CTO技術棧公眾號

国产精品久久国产三级国电话系列| 欧美成人免费网| 日日摸天天爽天天爽视频| www.亚洲视频| 大尺度一区二区| 日本成人黄色片| 丝袜美腿小色网| 午夜欧洲一区| 日韩欧美国产麻豆| 成人亚洲视频在线观看| 尤物在线网址| 国产精品素人一区二区| 国产精品久久久久av福利动漫| 九九热最新视频| 伊人久久综合| 色av中文字幕一区| 视频免费在线观看| 精品国产鲁一鲁****| 色综合天天综合| 成人黄色片免费| 你懂的免费在线观看视频网站| 韩国三级中文字幕hd久久精品| 69久久夜色精品国产69乱青草| 国产精品视频看看| 国产一区二区三区四区二区| 欧美videossexotv100| 噼里啪啦国语在线观看免费版高清版| 影院在线观看全集免费观看| 中文字幕va一区二区三区| 国产综合av一区二区三区| 国产精品欧美亚洲| 日本中文字幕一区二区视频 | 欧美日韩在线免费| 国产女主播av| 一区二区三区视频网站| 26uuu成人网一区二区三区| 91九色露脸| 国产又粗又猛又黄| 日本女人一区二区三区| 日韩av电影国产| 久草视频在线观| 亚洲五月婷婷| 欧美日韩第一页| 特级片在线观看| 欧美1区2区3区| 久久精品人人做人人爽| av最新在线观看| 婷婷综合网站| 日韩日本欧美亚洲| 亚洲女人毛茸茸高潮| 成人在线免费观看91| 亚洲色图17p| 波多野结衣 在线| 欧美日韩精品一区二区三区在线观看| 精品国产露脸精彩对白| 黑人玩弄人妻一区二区三区| 国产精品巨作av| 精品电影一区二区三区| youjizz.com国产| 猫咪成人在线观看| 亚洲欧美精品一区二区| 国产免费无遮挡吸奶头视频| 激情婷婷综合| 中文字幕日韩有码| 日本黄色录像视频| 欧美精品入口| 97视频com| 毛片基地在线观看| 日韩电影一二三区| 成人激情视频在线观看| www.国产黄色| 97aⅴ精品视频一二三区| 久久久久久久免费| 99中文字幕一区| 亚洲男人天堂av| 国产精品视频网站在线观看| 鲁鲁在线中文| 欧美在线免费观看亚洲| 想看黄色一级片| av男人一区| 伊人av综合网| 色欲人妻综合网| 亚洲精品字幕| 国产精品久久91| a天堂在线视频| 97成人超碰视| 亚洲欧美一二三| 成人影院在线视频| 欧美日韩另类一区| 婷婷五月精品中文字幕| 欧美日韩中文一区二区| 欧美成人在线免费| 亚洲GV成人无码久久精品| 麻豆成人综合网| 国产精品一区二| 色开心亚洲综合| 亚洲成a人v欧美综合天堂| 欧美 日韩 国产 激情| 精品国产亚洲一区二区在线观看| 亚洲激情在线观看视频免费| 国产91在线播放九色| 最新成人av网站| 国产一区二区香蕉| 台湾av在线二三区观看| 亚洲天堂精品视频| 国产成人无码av在线播放dvd| 国产麻豆一区二区三区| 亚洲午夜av电影| 日本三级2019| 韩国午夜理伦三级不卡影院| 欧美性大战久久久久| 免费在线中文字幕| 欧美日韩国产乱码电影| 日韩人妻一区二区三区 | 久久综合九色综合88i| 亚洲tv在线| 亚洲人成网站999久久久综合| 全网免费在线播放视频入口| 日本亚洲天堂网| 久久久久久99| 成人免费一区二区三区牛牛| 91精品国产91热久久久做人人| 中文字幕一二三四区| 1000部精品久久久久久久久| 91亚洲精品一区| 午夜国产福利在线| 欧美在线观看视频在线| 国产精品1000部啪视频| 亚洲一级一区| 痴汉一区二区三区| a视频在线播放| 欧美妇女性影城| 国产在视频线精品视频| 日韩av电影一区| 欧美性色黄大片人与善| 国产精品迅雷| 亚洲精品视频免费| 国产一级精品视频| 99久久夜色精品国产网站| 欧美一区二区视频在线播放| 我要色综合中文字幕| 精品久久久91| 国产乱码一区二区| 日韩美女精品在线| 三级黄色片免费看| 自拍偷拍欧美专区| 69堂成人精品视频免费| caoporn免费在线| 日韩午夜三级在线| 精品处破女学生| 成人免费高清在线| 婷婷无套内射影院| 国产99久久久国产精品成人免费 | 9久久9毛片又大又硬又粗| 一区二区三区四区高清视频| 欧美寡妇偷汉性猛交| 亚洲av无码乱码在线观看性色| 亚洲免费资源在线播放| 三上悠亚 电影| 黄色综合网站| 久久香蕉综合色| 伊人久久视频| 日韩在线视频二区| 99精品免费观看| 亚洲成人精品一区二区| 欧洲女同同性吃奶| 日本欧美在线观看| 成人污网站在线观看| 加勒比色老久久爱综合网| 欧美一级免费视频| av中文字幕一区二区三区| 欧美一区中文字幕| 日本天堂网在线观看| 久久精品人人做人人爽人人| 中文字幕 日韩 欧美| 狠狠综合久久| 日本一区网站| 亚洲精品一区二区三区在线| 91高清视频免费观看| 浮生影视网在线观看免费| 91精品蜜臀在线一区尤物| 国产真实乱偷精品视频| 久久综合狠狠综合久久综合88 | 福利一区在线观看| 97视频在线免费播放| 99热国内精品| 精品999在线观看| a屁视频一区二区三区四区| 欧美精品亚州精品| 国产小视频免费在线观看| 欧美裸体bbwbbwbbw| 欧美精品成人久久| 久久久国产精品不卡| 手机精品视频在线| 国产精品五区| 国产免费xxx| 国产欧美一区| 国产伦精品一区二区三区四区视频| 3d欧美精品动漫xxxx无尽| 久久国产色av| 国产1区2区3区在线| 精品国产区一区| 一级全黄少妇性色生活片| 香蕉久久一区二区不卡无毒影院| 欧美另类69xxxx| 久久先锋影音av鲁色资源| 亚洲视频在线不卡| 免费欧美在线视频| 日日鲁鲁鲁夜夜爽爽狠狠视频97 | 亚洲美免无码中文字幕在线 | 久久久亚洲精品石原莉奈| 日韩精品在线播放视频| 日本成人在线一区| 日本福利视频在线| 国内精品99| 国产免费一区二区三区四在线播放| 免费电影一区二区三区| 国产日产精品一区二区三区四区| 色综合久久久| 国产激情视频一区| 色在线中文字幕| 性欧美在线看片a免费观看| a级在线观看| 播播国产欧美激情| 91在线视频| 国产一区二区三区视频在线观看| 天堂成人在线视频| 日韩精品一区二区三区四区 | 精品视频久久久久久| 蜜桃视频污在线观看| 日韩欧美国产系列| 国产成人a人亚洲精品无码| 欧美精品第1页| 在线观看日韩一区二区| 91久久精品日日躁夜夜躁欧美| 全部毛片永久免费看| 亚洲国产综合视频在线观看| 久草成人在线视频| 一个色综合网站| 欧美激情精品久久| 亚洲一区精品在线| 日本免费在线播放| 偷拍日韩校园综合在线| 国产一级做a爰片在线看免费 | 69亚洲精品久久久蜜桃小说 | 免费观看黄色av| 亚洲成人在线视频播放| 日本免费网站在线观看| 亚洲第一精品夜夜躁人人躁| 欧美一级片免费| 亚洲国产精品字幕| 男人天堂综合| 亚洲最新视频在线| 99免在线观看免费视频高清| 色青青草原桃花久久综合| 免费超碰在线| 色综合导航网站| 国产福利电影在线播放| 欧美一级淫片aaaaaaa视频| 黑人巨大精品欧美一区二区桃花岛| 国产99视频在线观看| 日本精品在线中文字幕| 国产日韩专区在线| 日韩中文字幕一区二区高清99| 国产精品我不卡| 免费一区二区三区视频导航| 视频一区二区三| 一级毛片免费高清中文字幕久久网| 妞干网这里只有精品| 影音先锋亚洲精品| 久久精品香蕉视频| 九一九一国产精品| 丰满人妻一区二区三区免费视频棣| 91免费看视频| 国产又色又爽又高潮免费| 亚洲精品福利视频网站| 亚欧视频在线观看| 欧美日韩小视频| 亚洲乱码在线观看| 亚洲日本aⅴ片在线观看香蕉| 欧美成人视屏| 91精品国产高清久久久久久久久| 天然素人一区二区视频| 91久久伊人青青碰碰婷婷| 亚州综合一区| dy888午夜| 久久亚洲精选| 成人做爰69片免费| 亚洲国产精品激情在线观看| 欧美日韩精品亚洲精品| 91黄视频在线观看| 亚洲精品久久久狠狠狠爱 | 欧美丰满艳妇bbwbbw| 一本一本久久a久久精品综合麻豆 一本一道波多野结衣一区二区 | 在线免费观看黄色小视频| 亚洲欧美自拍偷拍色图| √资源天堂中文在线| 欧美日韩一区高清| 天天干天天操av| 久久久国产精彩视频美女艺术照福利| 国产乱码午夜在线视频| 91免费国产视频| 国产欧美高清视频在线| 欧美激情视频免费看| 久草在线在线精品观看| a级在线免费观看| 亚洲一区在线电影| 一区二区三区免费在线| 亚洲图片制服诱惑| 国产污视频在线播放| 91麻豆蜜桃| 国产精品7m凸凹视频分类| 成年人视频网站免费观看| 国产激情视频一区二区三区欧美| 日本污视频网站| 色综合一个色综合亚洲| 婷婷在线观看视频| 欧美激情在线视频二区| www一区二区三区| 亚洲一区精品视频| 日韩av中文在线观看| 国产高清自拍视频| 性做久久久久久| 丰满肉肉bbwwbbww| 美日韩精品免费观看视频| 日日夜夜亚洲精品| 午夜精品一区二区三区四区 | 亚洲第一色av| 国产精品美女久久久久久久| 国产成人精品亚洲| 在线观看日韩专区| 成人免费av电影| 日韩av高清| 日韩中文字幕区一区有砖一区| 噜噜噜在线视频| 大桥未久av一区二区三区| 欧美一级视频免费| 91精品国产91久久久久| 欧美a大片欧美片| 9久久9毛片又大又硬又粗| 成人av网站在线观看| 日本一区二区网站| 日韩av在线免播放器| 黄色视屏在线免费观看| 精品蜜桃传媒| 久久久久久穴| 成人无码av片在线观看| 欧美在线一区二区三区| 伊人免费在线| 亚洲aⅴ男人的天堂在线观看| 亚洲一区二区| 无码国产69精品久久久久网站| 亚洲一二三区在线观看| 同心难改在线观看| 日韩av毛片网| 91视频精品| 亚洲三级在线视频| 亚洲成人精品在线观看| 欧美日韩国产中文字幕在线| 国产精品www| 中文字幕一区二区三区在线视频 | 亚洲欧美日韩在线| 朝桐光av在线一区二区三区| 国外成人免费在线播放| 亚洲小说图片| 伊人国产在线视频| 亚洲一区在线视频| 亚洲av成人精品日韩在线播放| 日本人成精品视频在线| 久久高清精品| www.17c.com喷水少妇| 色系网站成人免费| 成人av福利| 欧美lavv| 国产一区二区精品在线观看| 久久9999久久免费精品国产| 亚洲无av在线中文字幕| 欧美h版在线观看| 北条麻妃在线观看| 亚洲乱码精品一二三四区日韩在线| 乱精品一区字幕二区| 国产精品美女呻吟| 亚洲网站视频| 天堂网av2018| 日韩电影视频免费| 高清一区二区中文字幕| 97国产精东麻豆人妻电影| 中文字幕一区二区三区av| 先锋av资源站| 亚洲在线免费视频| 乱码第一页成人| 国产亚洲色婷婷久久99精品| 这里只有精品视频在线| 国产精品视频3p| 污污网站免费观看| 欧美色视频日本高清在线观看| 久久精品视频免费看| 日本一区二区久久精品| 粉嫩一区二区三区性色av| 最近中文字幕在线免费观看|