在項目中用TS封裝axios,一次封裝團隊受益
作者:一碗周 原文:https://juejin.cn/post/7071518211392405541
寫在前面
雖然說Fetch API已經(jīng)使用率已經(jīng)非常的高了,但是在一些老的瀏覽器還是不支持的,而且axios仍然每周都保持2000多萬的下載量,這就說明了axios仍然存在不可撼動的地位,接下來我們就一步一步的去封裝,實現(xiàn)一個靈活、可復(fù)用的一個請求請發(fā)。
這篇文章封裝的axios已經(jīng)滿足如下功能:
無處不在的代碼提示; 靈活的攔截器; 可以創(chuàng)建多個實例,靈活根據(jù)項目進行調(diào)整; 每個實例,或者說每個接口都可以靈活配置請求頭、超時時間等; 取消請求(可以根據(jù)url取消單個請求也可以取消全部請求)。
基礎(chǔ)封裝
首先我們實現(xiàn)一個最基本的版本,實例代碼如下:
//?index.ts
import?axios?from?'axios'
import?type?{?AxiosInstance,?AxiosRequestConfig?}?from?'axios'
class?Request?{
??//?axios?實例
??instance:?AxiosInstance
??constructor(config:?AxiosRequestConfig)?{
????this.instance?=?axios.create(config)
??}
??request(config:?AxiosRequestConfig)?{
????return?this.instance.request(config)
??}
}
export?default?Request
這里將其封裝為一個類,而不是一個函數(shù)的原因是因為類可以創(chuàng)建多個實例,適用范圍更廣,封裝性更強一些。
攔截器封裝
首先我們封裝一下攔截器,這個攔截器分為三種:
類攔截器 實例攔截器 接口攔截器
接下來我們就分別實現(xiàn)這三個攔截器。
類攔截器
類攔截器比較容易實現(xiàn),只需要在類中對axios.create()創(chuàng)建的實例調(diào)用interceptors下的兩個攔截器即可,實例代碼如下:
//?index.ts
constructor(config:?AxiosRequestConfig)?{
??this.instance?=?axios.create(config)
??this.instance.interceptors.request.use(
????(res:?AxiosRequestConfig)?=>?{
??????console.log('全局請求攔截器')
??????return?res
????},
????(err:?any)?=>?err,
??)
??this.instance.interceptors.response.use(
????//?因為我們接口的數(shù)據(jù)都在res.data下,所以我們直接返回res.data
????(res:?AxiosResponse)?=>?{
??????console.log('全局響應(yīng)攔截器')
??????return?res.data
????},
????(err:?any)?=>?err,
??)
}
我們在這里對響應(yīng)攔截器做了一個簡單的處理,就是將請求結(jié)果中的.data進行返回,因為我們對接口請求的數(shù)據(jù)主要是存在在.data中,跟data同級的屬性我們基本是不需要的。
實例攔截器
實例攔截器是為了保證封裝的靈活性,因為每一個實例中的攔截后處理的操作可能是不一樣的,所以在定義實例時,允許我們傳入攔截器。
首先我們定義一下interface,方便類型提示,代碼如下:
//?types.ts
import?type?{?AxiosRequestConfig,?AxiosResponse?}?from?'axios'
export?interface?RequestInterceptors?{
??//?請求攔截
??requestInterceptors?:?(config:?AxiosRequestConfig)?=>?AxiosRequestConfig
??requestInterceptorsCatch?:?(err:?any)?=>?any
??//?響應(yīng)攔截
??responseInterceptors?:?(config:?AxiosResponse)?=>?AxiosResponse
??responseInterceptorsCatch?:?(err:?any)?=>?any
}
//?自定義傳入的參數(shù)
export?interface?RequestConfig?extends?AxiosRequestConfig?{
??interceptors?:?RequestInterceptors
}
定義好基礎(chǔ)的攔截器后,我們需要改造我們傳入的參數(shù)的類型,因為axios提供的AxiosRequestConfig是不允許我們傳入攔截器的,所以說我們自定義了RequestConfig,讓其繼承與AxiosRequestConfig 。
剩余部分的代碼也比較簡單,如下所示:
//?index.ts
import?axios,?{?AxiosResponse?}?from?'axios'
import?type?{?AxiosInstance,?AxiosRequestConfig?}?from?'axios'
import?type?{?RequestConfig,?RequestInterceptors?}?from?'./types'
class?Request?{
??//?axios?實例
??instance:?AxiosInstance
??//?攔截器對象
??interceptorsObj?:?RequestInterceptors
??constructor(config:?RequestConfig)?{
????this.instance?=?axios.create(config)
????this.interceptorsObj?=?config.interceptors
????this.instance.interceptors.request.use(
??????(res:?AxiosRequestConfig)?=>?{
????????console.log('全局請求攔截器')
????????return?res
??????},
??????(err:?any)?=>?err,
????)
????//?使用實例攔截器
????this.instance.interceptors.request.use(
??????this.interceptorsObj?.requestInterceptors,
??????this.interceptorsObj?.requestInterceptorsCatch,
????)
????this.instance.interceptors.response.use(
??????this.interceptorsObj?.responseInterceptors,
??????this.interceptorsObj?.responseInterceptorsCatch,
????)
????//?全局響應(yīng)攔截器保證最后執(zhí)行
????this.instance.interceptors.response.use(
??????//?因為我們接口的數(shù)據(jù)都在res.data下,所以我們直接返回res.data
??????(res:?AxiosResponse)?=>?{
????????console.log('全局響應(yīng)攔截器')
????????return?res.data
??????},
??????(err:?any)?=>?err,
????)
??}
}
我們的攔截器的執(zhí)行順序為實例請求→類請求→實例響應(yīng)→類響應(yīng);這樣我們就可以在實例攔截上做出一些不同的攔截,
接口攔截
現(xiàn)在我們對單一接口進行攔截操作,首先我們將AxiosRequestConfig類型修改為RequestConfig允許傳遞攔截器;然后我們在類攔截器中將接口請求的數(shù)據(jù)進行了返回,也就是說在request()方法中得到的類型就不是AxiosResponse類型了。
我們查看axios的index.d.ts中,對request()方法的類型定義如下:
//?type.ts
requestany,?R?=?AxiosResponse,?D?=?any>(config:?AxiosRequestConfig):?Promise;
也就是說它允許我們傳遞類型,從而改變request()方法的返回值類型,我們的代碼如下:
//?index.ts
request(config:?RequestConfig):?Promise?{
??return?new?Promise((resolve,?reject)?=>?{
????//?如果我們?yōu)閱蝹€請求設(shè)置攔截器,這里使用單個請求的攔截器
????if?(config.interceptors?.requestInterceptors)?{
??????config?=?config.interceptors.requestInterceptors(config)
????}
????this.instance
??????.request<any,?T>(config)
??????.then(res?=>?{
????????//?如果我們?yōu)閱蝹€響應(yīng)設(shè)置攔截器,這里使用單個響應(yīng)的攔截器
????????if?(config.interceptors?.responseInterceptors)?{
??????????res?=?config.interceptors.responseInterceptors(res)
????????}
????????resolve(res)
??????})
??????.catch((err:?any)?=>?{
????????reject(err)
??????})
??})
}
這里還存在一個細節(jié),就是我們在攔截器接受的類型一直是AxiosResponse類型,而在類攔截器中已經(jīng)將返回的類型改變,所以說我們需要為攔截器傳遞一個泛型,從而使用這種變化,修改types.ts中的代碼,示例如下:
//?index.ts
export?interface?RequestInterceptors?{
??//?請求攔截
??requestInterceptors?:?(config:?AxiosRequestConfig)?=>?AxiosRequestConfig
??requestInterceptorsCatch?:?(err:?any)?=>?any
??//?響應(yīng)攔截
??responseInterceptors?:?(config:?T)?=>?T
??responseInterceptorsCatch?:?(err:?any)?=>?any
}
請求接口攔截是最前執(zhí)行,而響應(yīng)攔截是最后執(zhí)行。
封裝請求方法
現(xiàn)在我們就來封裝一個請求方法,首先是類進行實例化示例代碼如下:
//?index.ts
import?Request?from?'./request'
const?request?=?new?Request({
??baseURL:?import.meta.env.BASE_URL,
??timeout:?1000?*?60?*?5,
??interceptors:?{
????//?請求攔截器
????requestInterceptors:?config?=>?{
??????console.log('實例請求攔截器')
??????return?config
????},
????//?響應(yīng)攔截器
????responseInterceptors:?result?=>?{
??????console.log('實例響應(yīng)攔截器')
??????return?result
????},
??},
})
然后我們封裝一個請求方法, 來發(fā)送網(wǎng)絡(luò)請求,代碼如下:
//?src/server/index.ts
import?Request?from?'./request'
import?type?{?RequestConfig?}?from?'./request/types'
interface?YWZRequestConfig?extends?RequestConfig?{
??data?:?T
}
interface?YWZResponse?{
??code:?number
??message:?string
??data:?T
}
/**
?*?@description:?函數(shù)的描述
?*?@interface?D?請求參數(shù)的interface
?*?@interface?T?響應(yīng)結(jié)構(gòu)的intercept
?*?@param?{YWZRequestConfig}?config?不管是GET還是POST請求都使用data
?*?@returns?{Promise}
?*/
const?ywzRequest?=?any>(config:?YWZRequestConfig )?=>?{
??const?{?method?=?'GET'?}?=?config
??if?(method?===?'get'?||?method?===?'GET')?{
????config.params?=?config.data
??}
??return?request.request>(config)
}
export?default?ywzRequest
該請求方式默認為GET,且一直用data作為參數(shù);
取消請求
應(yīng)評論區(qū)@Pic、@Michaelee和@Alone_Error的建議,這里增加了一個取消請求;關(guān)于什么是取消請求可以參考官方文檔[1]。
準(zhǔn)備工作
我們需要將所有請求的取消方法保存到一個集合(這里我用的數(shù)組,也可以使用Map)中,然后根據(jù)具體需要去調(diào)用這個集合中的某個取消請求方法。
首先定義兩個集合,示例代碼如下:
//?index.ts
import?type?{
??RequestConfig,
??RequestInterceptors,
??CancelRequestSource,
}?from?'./types'
class?Request?{
??/*
??存放取消方法的集合
??*?在創(chuàng)建請求后將取消請求方法?push?到該集合中
??*?封裝一個方法,可以取消請求,傳入?url:?string|string[]
??*?在請求之前判斷同一URL是否存在,如果存在就取消請求
??*/
??cancelRequestSourceList?:?CancelRequestSource[]
??/*
??存放所有請求URL的集合
??*?請求之前需要將url?push到該集合中
??*?請求完畢后將url從集合中刪除
??*?添加在發(fā)送請求之前完成,刪除在響應(yīng)之后刪除
??*/
??requestUrlList?:?string[]
??constructor(config:?RequestConfig)?{
????//?數(shù)據(jù)初始化
????this.requestUrlList?=?[]
????this.cancelRequestSourceList?=?[]
??}
}
這里用的CancelRequestSource接口,我們?nèi)ザx一下:
//?type.ts
export?interface?CancelRequestSource?{
??[index:?string]:?()?=>?void
}
這里的key是不固定的,因為我們使用url做key,只有在使用的時候才知道url,所以這里使用這種語法。
取消請求方法的添加與刪除
首先我們改造一下request()方法,它需要完成兩個工作,一個就是在請求之前將url和取消請求方法push到我們前面定義的兩個屬性中,然后在請求完畢后(不管是失敗還是成功)都將其進行刪除,實現(xiàn)代碼如下:
//?index.ts
request(config:?RequestConfig):?Promise?{
??return?new?Promise((resolve,?reject)?=>?{
????//?如果我們?yōu)閱蝹€請求設(shè)置攔截器,這里使用單個請求的攔截器
????if?(config.interceptors?.requestInterceptors)?{
??????config?=?config.interceptors.requestInterceptors(config)
????}
????const?url?=?config.url
????//?url存在保存取消請求方法和當(dāng)前請求url
????if?(url)?{
??????this.requestUrlList?.push(url)
??????config.cancelToken?=?new?axios.CancelToken(c?=>?{
????????this.cancelRequestSourceList?.push({
??????????[url]:?c,
????????})
??????})
????}
????this.instance
??????.request<any,?T>(config)
??????.then(res?=>?{
????????//?如果我們?yōu)閱蝹€響應(yīng)設(shè)置攔截器,這里使用單個響應(yīng)的攔截器
????????if?(config.interceptors?.responseInterceptors)?{
??????????res?=?config.interceptors.responseInterceptors(res)
????????}
????????resolve(res)
??????})
??????.catch((err:?any)?=>?{
????????reject(err)
??????})
??????.finally(()?=>?{
????????url?&&?this.delUrl(url)
??????})
??})
}
這里我們將刪除操作進行了抽離,將其封裝為一個私有方法,示例代碼如下:
//?index.ts
/**
?*?@description:?獲取指定?url?在?cancelRequestSourceList?中的索引
?*?@param?{string}?url
?*?@returns?{number}?索引位置
?*/
private?getSourceIndex(url:?string):?number?{
??return?this.cancelRequestSourceList?.findIndex(
????(item:?CancelRequestSource)?=>?{
??????return?Object.keys(item)[0]?===?url
????},
??)?as?number
}
/**
?*?@description:?刪除?requestUrlList?和?cancelRequestSourceList
?*?@param?{string}?url
?*?@returns?{*}
?*/
private?delUrl(url:?string)?{
??const?urlIndex?=?this.requestUrlList?.findIndex(u?=>?u?===?url)
??const?sourceIndex?=?this.getSourceIndex(url)
??//?刪除url和cancel方法
??urlIndex?!==?-1?&&?this.requestUrlList?.splice(urlIndex?as?number,?1)
??sourceIndex?!==?-1?&&
????this.cancelRequestSourceList?.splice(sourceIndex?as?number,?1)
}
取消請求方法
現(xiàn)在我們就可以封裝取消請求和取消全部請求了,我們先來封裝一下取消全部請求吧,這個比較簡單,只需要調(diào)用this.cancelRequestSourceList中的所有方法即可,實現(xiàn)代碼如下:
//?index.ts
//?取消全部請求
cancelAllRequest()?{
??this.cancelRequestSourceList?.forEach(source?=>?{
????const?key?=?Object.keys(source)[0]
????source[key](?"key")
??})
}
現(xiàn)在我們封裝一下取消請求,因為它可以取消一個和多個,那它的參數(shù)就是url,或者包含多個URL的數(shù)組,然后根據(jù)傳值的不同去執(zhí)行不同的操作,實現(xiàn)代碼如下:
//?index.ts
//?取消請求
cancelRequest(url:?string?|?string[])?{
??if?(typeof?url?===?'string')?{
????//?取消單個請求
????const?sourceIndex?=?this.getSourceIndex(url)
????sourceIndex?>=?0?&&?this.cancelRequestSourceList?.[sourceIndex][url](?"sourceIndex][url")
??}?else?{
????//?存在多個需要取消請求的地址
????url.forEach(u?=>?{
??????const?sourceIndex?=?this.getSourceIndex(u)
??????sourceIndex?>=?0?&&?this.cancelRequestSourceList?.[sourceIndex][u](?"sourceIndex][u")
????})
??}
}
測試
測試請求方法
現(xiàn)在我們就來測試一下這個請求方法,這里我們使用www.apishop.net/[2]提供的免費API進行測試,測試代碼如下:
<script?setup?lang="ts">
//?app.vue
import?request?from?'./service'
import?{?onMounted?}?from?'vue'
interface?Req?{
??apiKey:?string
??area?:?string
??areaID?:?string
}
interface?Res?{
??area:?string
??areaCode:?string
??areaid:?string
??dayList:?any[]
}
const?get15DaysWeatherByArea?=?(data:?Req)?=>?{
??return?request({
????url:?'/api/common/weather/get15DaysWeatherByArea',
????method:?'GET',
????data,
????interceptors:?{
??????requestInterceptors(res)?{
????????console.log('接口請求攔截')
????????return?res
??????},
??????responseInterceptors(result)?{
????????console.log('接口響應(yīng)攔截')
????????return?result
??????},
????},
??})
}
onMounted(async?()?=>?{
??const?res?=?await?get15DaysWeatherByArea({
????apiKey:?import.meta.env.VITE_APP_KEY,
????area:?'北京市',
??})
??console.log(res.result.dayList)
})
script>
如果在實際開發(fā)中可以將這些代碼分別抽離。
上面的代碼在命令中輸出
接口請求攔截
實例請求攔截器
全局請求攔截器
實例響應(yīng)攔截器
全局響應(yīng)攔截器
接口響應(yīng)攔截
[{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…},?{…}]
測試取消請求
首先我們在.server/index.ts中對取消請求方法進行導(dǎo)出,實現(xiàn)代碼如下:
//?取消請求
export?const?cancelRequest?=?(url:?string?|?string[])?=>?{
??return?request.cancelRequest(url)
}
//?取消全部請求
export?const?cancelAllRequest?=?()?=>?{
??return?request.cancelAllRequest()
}
然后我們在app.vue中對其進行引用,實現(xiàn)代碼如下:
??????@click="cancelRequest('/api/common/weather/get15DaysWeatherByArea')"
????>取消請求</el-button
??>
??取消全部請求 el-button>
??</router-view>
template>
亚洲中文字幕在线视频观看|
青青精品视频|
国产性受XXXXXYX性爽|
国产一道本|
蜜桃性爱视频|
九九福利视频|
一区二区无码在线|
996热|
五月天激情综合|
18禁裸体美女|
亚洲国产成人视频|
高清无码免费看|
操人妻|
大香蕉久|
狼人综合影院|
久久国产精品99久久人人澡|
又黄又爽的网站|
79色色|
在线观看无码|
凸凹翔田千里无码|
天天操夜夜爱|
淫淫五月天|
一区二区三区AV|
日韩中文字幕成人|
婷婷国产成人精品视频|
99xxxxx|
欧美性网|
欧美日韩四区|
性爱免费视频网站|
囯产精品久久久久久久|
国产精品免费观看视频|
人人看人人爽|
欧美视频手机在线|
久久久久久久免费无码|
蜜桃视频在线入口www|
91无码精品|
伊人性视频|
色色五月天网站|
国产精品三级在线观看|
18禁黄网站|
在线视频福利|
亚洲成人影片在线观看|
亚洲黄色电影网站|
插入综合网|
加勒比综合网|
91精品国自产在线观看|
成人AV免费|
波多野结衣无码一区|
AV大全在线观看|
精品无码一区二区三区爱与|
91一区在线观看|
成人区人妻精品一|
大香伊人网|
国产老女人操逼视频|
91青青草在线|
色中文字幕|
亚洲网站在线免费观看|
91av免费在线观看|
日本日韩欧美|
精品国产久久久久|
AV手机在线|
国产AV福利|
骚色综合|
日韩少妇无码视频|
无码三级在线观看|
日韩三级视频在线观看|
亚洲日韩免费视频|
大香蕉一区|
国产美女网站|
熟女人妻ThePorn|
国产熟女视频|
亚洲成人视频网|
喷水在线观看|
欧美日韩国产尤物主播精品|
中国一级片|
中文精品字幕人妻熟女|
久久久女女女女999久久|
做爰视频毛片下载蜜桃视频|
亚洲黄色网址|
一级一级a免一级a做免费线看内裤|
亚洲成人久久久|
逼逼75大秀|
欧美日韩在线视频免费观看|
2017人人操|
老熟女网站|
久久亚洲av|
丁香色婷婷五月天|
欧美aaa视频|
黄片网站在线观看|
久久人人操人人|
天天日天天射天天操|
国产免费乱伦|
人妻精品久久久久中文字幕69|
亚洲人妻视频|
中文无码一区二区三区四区|
亚洲h|
国产3p露脸普通话对白|
国产成人无码在线|
亚洲中文字幕日韩在线|
操屄网|
手机看片福利一区二区|
丰满人妻一区二区三区免费|
黄色操逼视频|
在线观看的AV|
日韩99|
特黄AAAAAAAA片免费直播
|
三级精品|
在线不卡无码|
日韩激情无码一区二区|
男女AV在线免费观看|
韩日无码视频|
欧美精品操逼|
亚洲黄视频|
www.色中色|
亚洲久久久久|
日本无码成人片在线播放|
欧美自拍视频在线观看|
人妻18无码人伦一区二区三区精品|
最近最好的2019中文|
欧美午夜影院|
天天日天天舔|
亚洲AV成人一区二区三区不卡|
精品无码专区|
日韩AV无码专区亚洲AV紧身裤
|
久青操|
天天日夜夜草|
蜜桃网站视频|
伊人网大香|
激情五月天av|
污视频免费在线观看|
永久免费AV无码|
亚洲午夜剧场|
二区不卡|
久久99高清视频|
特级毛片WWW|
婷婷在线影院|
A级无码|
jizz久久|
成人片天天看片欧美一级|
国产办公室丝袜人妖|
啪啪A片|
人人人人操|
新BBWBBWBBWBBW|
久久久成人电影|
骚妇大战黑人15P|
国产成人A∨|
黑人丰满大荫蒂|
成人亚洲综合|
91热99|
天天日夜夜艹|
国产精品自拍在线观看|
色综合久|
国产精品久久久久久久牛牛|
久久草|
91精品久久久久久久久|
91一级A片在线观看|
国产一级大片|
99在线视频免费|
大地资源第三页在线观看免费播放最新|
成人电影一区|
人人操人人摸人人爽|
亚州加勒比无码|
99色综合|
www.欧美视频|
欧美激情内射|
狠狠干影院|
亚洲无码高清在线视频|
老湿机91|
99这里只有精品视频|
99热综合在线|
亚洲AV无码成人精品久久久|
A级无码|
国产女人18毛片水18精品|
高清毛片AAAAAAAAA片|
成人精品在线视频|
婷婷五月无码|
操久在线|
国产高清AV|
干干日日|
伊人久久香蕉网|
成人a片在线免费观看|
黄色小视频免费看|
亚洲AV无码乱码国产|
亚洲免费MV|
91在线播放视频|
蜜桃Av噜噜一区|
久久精品99国产国产精|
青青草av|
国产福利电影在线观看|
成人美女视频|
色五月视频在线|
日韩国产在线|
国产真实乱婬A片三区高清蜜臀|
精品中文在线|
国产精品H|
99热这里都是精品|
四虎精品一区二区|
12—13女人毛片毛片|
日本三级片中文字幕|
中文字幕在线免费看|
中文字幕在线有码|
日韩精品在线免费|
国产精品自拍在线观看|
亚洲福利久久|
操比视频|
国产二区三区|
亚洲精品中文字幕成人片|
男人的天堂视频在线|
在线观看av中文字幕|
国内自拍偷拍|
日韩成人A片|
无码人妻丰满熟妇区蜜桃|
高清无码小视频|
亚洲一二期视频|
一区二区三区免费观看|
欧美午夜网站|
亚州成人视频|
婷婷午夜精品久久久久久性色|
亚洲欧美日韩免费|
无码av亚洲一区二区毛片公司|
女人天堂AV|
欧美亚洲日本|
成人黄色AV|
国产精品久久毛片|
欧美一区二区三区四|
大地8免费高清视频观看大全|
亚洲精品一区二区三区在线观看
|
Japanese在线观看|
可以免费看av的网站|
人妻中文字幕av|
精品九九九九九九|
久久成人123|
久久免费精品视频|
www.国产在线观看|
大香蕉精品在线视频|
夜夜操天天日|
在线观看免费黄网站|
久久av网站|
婷婷A片|
玖玖爱资源站|
丹麦电影《下午》|
美女被操免费网站|
日本黄色三级视频|
日韩免费黄色电影|
日本国产在线观看|
h片网站在线观看|
婷婷五月天色播|
国产精品视频色|
黄片WWW|
中文字幕在线欧美|
这里只有精品91|
99电影网手机在线观看|
91香蕉视频18|
免费黄色在线视频|
日本一级黃色大片看免费|
久久男人天堂|
丰满少妇一区二区三区|
亚州av|
家庭乱伦av|
一级黄色小视频|
日韩中文无码字幕|
91大神在线观看入口|
韩国免费一级a一片在线播放|
www.xxx国产|
特级444www|
少妇搡BBBB搡BBB搡小说
|
91精品丝袜久久久久久久久粉嫩|
亚洲女人视频|
懂色AV一区二区三区国产中文在线
|
日韩操比视频|
台湾成人在线视频|
久久你懂的|
激情一区|
午夜操逼|
日本久久久久久久久视频在线观看
|
中文字幕无码综合|
天天拍夜夜爽|
在线视频观看一区|
大地资源中文第二页导读内容|
亚洲va欧美va|
久久撸在线视频|
91婷婷在线|
日本豆花视频|
成人精品一区日本无码网站suv/|
免费观看亚洲视频|
撸一撸免费视频|
久久综合17p|
乱伦婷婷|
韩国三级HD久久精品|
国产免费无码视频|
一区二区在线看|
偷拍二区|
AV片在线免费观看|
成人激情在线观看|
成人午夜无码福利视频|
女人的天堂av|
麻豆精品|
免费黄色小视频|
99极品视频|
五月花在线视频|
