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

iOS網絡層架構設計分享

移動開發
前些天幫公司做了網絡層的重構,當時就想做好了就分享給大家,后來接著做了新版本的需求,現在才有時間整理一下。

[[166105]]

前言

前些天幫公司做了網絡層的重構,當時就想做好了就分享給大家,后來接著做了新版本的需求,現在才有時間整理一下。

之前的網絡層使用的是直接拖拽導入項目的方式導入了AF,然后還修改了大量的源碼,時隔2年,AF已經更新換代很多次了,導致整個重構遷移非常的麻煩。不過看著前輩寫的代碼,肯定也是一個高人,許多思路和我的一樣,但是實現方式又不同,給我很好的參考。

在做網絡層架構的時候也參考了Casa大神的架構思想,但是還是有所不同。

本文沒有太多的理論,沒有太多的專業術語,一來是方便大家閱讀,二來我的基礎也沒那么好,沒有太多華麗的詞匯,對于架構來說主要是思路,有思路在,具體的實現就沒有問題了。

本文主要介紹以下幾點:

1.網絡接口規范

2.多服務器多環境設置

3.網絡層數據傳遞(請求和返回)

4.業務層對接方式

5.網絡請求怎么自動取消

6.網絡層錯誤處理

無Demo無文章,Demo下載:https://github.com/SummertimSadness/NetWorkingDemo

網絡接口規范

demo里面的請求示例是在網上找的,不符合我說的這套規范,僅作示例用

規范很重要,有合理的規范就可以精簡很多代碼邏輯,特別是接口的兼容,是最底層最基礎的設計,把接口規范放在前面來說

在做這次重構時,我提出了一些規范點,可以給大家參考

1.兩層三部分數據結構

接口返回數據第一次為字典,分為兩層三部分:code、msg、data

  1. "code"0
  2. "msg"""
  3. "data": { 
  4.     "upload_log"true
  5.     "has_update"false
  6.     "admin_id""529ecfd64" 
  • code:錯誤碼,可以記錄下來快速定位接口錯誤原因,可以定義一套錯誤碼,比如200正常,1重新登錄...

  • msg:接口文案提示,包括錯誤提示,用來直接顯示給用戶,所以這一套錯誤提示就不能是什么一串英文錯誤了

  • data:需要返回的數據,可以是字典,可以是數組

接口幫我們定義了code和msg,是不是我們就不需要做錯誤處理了?當然不是,服務端的錯誤邏輯畢竟是簡單的,具體到data里面的數據處理可能還有錯誤,所以錯誤的處理是必不可少的,下面會單獨對錯誤處理做介紹

2.網絡請求參數上傳方式統一

這里一般都能做到,也有額外的,比如我們的一個服務器接口做的比較早,當時POST接口使用的就不規范,普通的應用信息channelID、device_id使用的是拼接在字符串后面的方式,而真正的請求參數則需要轉成json放在一個字段里面傳遞,就是接口GET、POST并存的方式,造成網絡層需要做特殊處理

所以說標準的GET、POST請求方式是很有必要的

3.關于Null類型

大家都知道Null類型在iOS里面是很特殊的,我的建議是放在客戶端來做,原因有很多:

1)接口的規范定義并不是每個公司都是從一開始就能定義好的,老接口如果要把Null字段去掉的改動非常大

2)客戶端用過一個接口過濾也可以解決,一勞永逸,不用再擔心因為某天接口的問題出現崩潰,而且通過一些Model的第三方庫也可以很好的解決這個問題。這里不得說下swift的類型檢測真是太方便了,之前一個項目用swift寫的,代碼規范一點,根本不會出現因為參數類型問題引起崩潰

多服務器多環境設置

這部分基本上是照搬casa大神的設計,這里我延伸了一個多環境的設計,小的項目一般都是一個服務器,但是像淘寶之類的項目一個服務器顯然是不可能的,多個服務器的設計還是非常普遍的。根據一個枚舉變量通過ServerFactory單例生成獲取對應的服務器配置

1.服務器環境

標準的APP是有4個環境的,開發、測試、預發、正式,特別是服務器的代碼,不能說所有的代碼更改都在正式環境下,應該從開發->測試->預發->正式做代碼的更新,開發就是新需求和優化的時候的更改,測試就是提交給測試人員后的更改,這個時候更改是在一個新的分支上,完成后要和合并到測試分支上并合并到開發分支上,預發這時候的變動就比較小了,一般會在測試人員完成后發布給全公司的人來測試,有問題了才會更改,更改后同樣合并到開發分支,正式則是線上發布版本的緊急BUG修復,修改完后同樣合并到開發分支上。所以開發分支是一直都是最新的。在此基礎上可能會有其他的環境,比如hotfix環境,自定義的h5/后臺本地調試的環境。

客戶端同樣存在這些環境,并且要提供切換的入口。

在我的demo中提供了兩套設置,一套是第一次安裝應用的初始化環境(宏定義),另外是手動切換環境的設置(枚舉EnvironmentType)。這里有一個比較繞的邏輯,宏定義的正式環境設置高于手動切換環境設置,手動切換環境設置高于宏定義其他環境

  1. //宏定義環境設置 
  2. #if !defined YA_BUILD_FOR_DEVELOP && !defined YA_BUILD_FOR_TEST && !defined YA_BUILD_FOR_RELEASE && !defined YA_BUILD_FOR_PRERELEASE 
  3. #define YA_BUILD_FOR_DEVELOP 
  4. //#define YA_BUILD_FOR_TEST 
  5. //#define YA_BUILD_FOR_PRERELEASE 
  6. //#define YA_BUILD_FOR_HOTFIX 
  7. //#define YA_BUILD_FOR_RELEASE      //該環境的優先級最高 
  8. #endif 
  9. //手動環境切換設置 
  10. #ifdef YA_BUILD_FOR_RELEASE 
  11. //優先宏定義正式環境 
  12. self.environmentType = EnvironmentTypeRelease; 
  13. #else 
  14. //手動切換環境后會把設置保存 
  15. NSNumber *type = [[NSUserDefaults standardUserDefaults] objectForKey:@"environmentType"]; 
  16. if (type) { 
  17.     //優先讀取手動切換設置 
  18.     self.environmentType = (EnvironmentType)[type integerValue]; 
  19. else { 
  20.     #ifdef YA_BUILD_FOR_DEVELOP 
  21.     self.environmentType = EnvironmentTypeDevelop; 
  22.     #elif defined YA_BUILD_FOR_TEST 
  23.     self.environmentType = EnvironmentTypeTest; 
  24.     #elif defined YA_BUILD_FOR_PRERELEASE 
  25.     self.environmentType = EnvironmentTypePreRelease; 
  26.     #elif defined YA_BUILD_FOR_HOTFIX 
  27.     self.environmentType = EnvironmentTypeHotFix; 
  28.     #endif 
  29. #endif 

所以當宏定義正式環境存在的時候是不能手動切換環境的,用于普通用戶的發布版本,但是其他宏定義環境時是可以切換到正式環境的。

半個坑

另外手動切換自定義的環境是在基類中實現的,而其他的環境配置是在協議中實現的,這就和其他環境地址的配置不統一了。

可以這樣理解,這里的基類是為了提供已返回值,協議是為了返回值的靈活,既然自定義環境的地址配置不需要靈活性,自然是放在基類好。思路是大方向,實現是靈活的,如果非要放在協議中實現也無不可以,無非是賦值粘貼幾次一樣的代碼,但是一模一樣的代碼是我最不喜歡看到的,所以就放在基類了。如果有更好的解決方案歡迎提供

2.擴展性

model提供的是高擴展性,針對不同的不服務器添加更多的配置,比如加密方法,比如數據解析方法...前面提到了,統一的規范有的時候不是一時半會就能做好的,兼容就成了需求,這個時候不同服務器的個性化設置就可以在協議中聲明并實現了,基類提供返回值就好

網絡層數據傳遞(請求和返回)

網絡層數據傳遞

Client、BaseEngine/DataEngine、RequestDataModel數據傳遞

網絡請求的發生在我理解中分兩步,一步是數據的整理,一步是生成Request并發起請求,基于這個思想我拆分出了Client和Engine,然后又把URLRequestGenerator從Client中拆分出來,Engine拆分出了下層的BaseEngine和面向不同業務的DataEngine,

而從BaseEngine到Client,再到URLRequestGenerator是要做數據傳遞的,請求參數和返回參數,所以又有了RequestDataModel

RequestDataModel

  1. @interface YAAPIBaseRequestDataModel : NSObject 
  2. /** 
  3. *  網絡請求參數 
  4. */ 
  5. @property (nonatomic, strong) NSString *apiMethodPath;              //網絡請求地址 
  6. @property (nonatomic, assign) YAServiceType serviceType;            //服務器標識 
  7. @property (nonatomic, strong) NSDictionary *parameters;             //請求參數 
  8. @property (nonatomic, assign) YAAPIManagerRequestType requestType;  //網絡請求方式 
  9. @property (nonatomic, copy) CompletionDataBlock responseBlock;      //請求著陸回調 
  10. // upload 
  11. // upload file 
  12. @property (nonatomic, strong) NSString *dataFilePath; 
  13. @property (nonatomic, strong) NSString *dataName; 
  14. @property (nonatomic, strong) NSString *fileName; 
  15. @property (nonatomic, strong) NSString *mimeType; 
  16. // download 
  17. // download file 
  18. // progressBlock 
  19. @property (nonatomic, copy) ProgressBlock uploadProgressBlock; 
  20. @property (nonatomic, copy) ProgressBlock downloadProgressBlock; 
  21. @end 

可以看出來RequestDataModel屬性都是網絡請求發起和返回的必要參數,這樣做的好處真的是太大了,不知道大家有沒有這樣的場景:因為請求參數的不同做了好多方法接口暴露出去,最后調起的還是同一個方法,而且一旦方法寫的多了,最后連應該調用哪個方法都不知道了。我就遇到過,所以現在我的網絡請求調起是這樣的:

  1. //沒有回調,沒有其他的參數,只有一個dataModel,節省了你所有的方法 
  2. [[YAAPIClient sharedInstance] callRequestWithRequestModel:dataModel]; 

生成NSURLRequest是這樣的:

  1. NSURLRequest *request = [[YAAPIURLRequestGenerator sharedInstance] generateWithYAAPIRequestWithRequestDataModel:requestModel]; 

可以看到我的demo里面的YAAPIClient類和YAAPIURLRequestGenerator類方法至少,方法少就意味著邏輯簡單明了,方便閱讀,兩個類的代碼行數都是120行,120行實現了網絡請求的發起和著陸,你能想象嗎

另外RequestDataModel帶來的另外一個好處就是高擴展性,你有沒有遇到網絡層需要添加刪除一個參數導致調用方法修改了,然后很多地方都要修改方法?用RequestDataModel只需要添加刪除參數就行了,只需要改方法體,這個改方法體和同時改方法名方法體是完全兩個工作量。哈哈,有點賣虎皮膏藥的感覺。這個的確是我的得意創新點

Client

Client做兩個操作,一個是生成NSURLRequest,一個是生成NSURLSessionDataTask并發起,另外還要暴露取消操作給Engine,

URLRequestGenerator是生成NSURLRequest,URLRequestGenerator會對dataModel進行加工解析,生成對應服務器的NSURLRequest

然后Client通過NSURLRequest生成NSURLSessionDataTask

Client和URLRequestGenerator都是單例

  1. - (void)callRequestWithRequestModel:(YAAPIBaseRequestDataModel *)requestModel{ 
  2.     NSURLRequest *request = [[YAAPIURLRequestGenerator sharedInstance] 
  3.     generateWithRequestDataModel:requestModel]; 
  4.     AFURLSessionManager *sessionManager = self.sessionManager; 
  5.     NSURLSessionDataTask *task = [sessionManager 
  6.     dataTaskWithRequest:request 
  7.     uploadProgress:requestModel.uploadProgressBlock 
  8.     downloadProgress:requestModel.downloadProgressBlock 
  9.     completionHandler:^(NSURLResponse * _Nonnull response, 
  10.     id  _Nullable responseObject, 
  11.     NSError * _Nullable error) 
  12.     { 
  13.         //請求著陸 
  14.     }]; 
  15.     [task resume]; 

取消接口參考了casa大神的設計,使用NSNumber *requestID來做task的綁定,就不多做介紹了

BaseEngine/DataEngine

Engine或者說是APIManager在我的設計中既不是離散的也不是集約的

casa大神的理論

集約型API調用其實就是所有API的調用只有一個類,然后這個類接收API名字,API參數,以及回調著陸點(可以是target-action,或者block,或者delegate等各種模式的著陸點)作為參數。然后執行類似startRequest這樣的方法,它就會去根據這些參數起飛去調用API了,然后獲得API數據之后再根據指定的著陸點去著陸。比如這樣:

  1. [APIRequest startRequestWithApiName:@"itemList.v1" params:params success:@selector(success:) fail:@selector(fail:) target:self]; 

離散型API調用是這樣的,一個API對應于一個APIManager,然后這個APIManager只需要提供參數就能起飛,API名字、著陸方式都已經集成入APIManager中。比如這樣:

  1. @property (nonatomic, strong) ItemListAPIManager *itemListAPIManager; 
  2. // getter 
  3. -(ItemListAPIManager *)itemListAPIManager 
  4.     if (_itemListAPIManager == nil) { 
  5.         _itemListAPIManager = [[ItemListAPIManager alloc] init]; 
  6.         _itemListAPIManager.delegate = self; 
  7.     } 
  8.     return _itemListAPIManager; 
  9. // 使用的時候就這么寫: 
  10. [self.itemListAPIManager loadDataWithParams:params]; 

各自的優點就不說了,但是由此延伸出幾個問題:

1.參數的傳遞使用字典對于網絡層來說是不可知的,而且業務層需要去關注接口字段的變化,其實是沒有必要的

2.離散型API會造成Manager大爆炸

3.集約型會造成取消操作不方便

4.取消操作并不是每個接口必須的,如果寫成部分離散的部分集約的,代碼的整體結構...我是個有強迫癥的人,看不得這樣的代碼

所以我的設計主要就解決了上面的這些問題

1.面向業務層的DataEngine只傳遞必要的參數進來,不使用字典,比如

  1. @interface SearchDataEngine : NSObject 
  2. + (YABaseDataEngine *)control:(NSObject *)control 
  3. searchKey:(NSString *)searchKey 
  4. complete:(CompletionDataBlock)responseBlock; 
  5. @end 

control暫時先不管,是做自動取消的,后面再介紹。

searchKey就是搜索的關鍵字

在調用的時候就是這樣

  1. self.searchDataEngine = [SearchDataEngine control:self searchKey:@"關鍵字" complete:^(id data, NSError *error) { 
  2.     if (error) { 
  3.         NSLog(@"%@",error.localizedDescription); 
  4.     } else { 
  5.         NSLog(@"%@",data); 
  6.     } 
  7. }]; 

2.我按業務層來劃分DataEngine,比如BBSDataEngine、ShopDataEngine、UserInforDataEngine...每個DataEngine里面包含各自業務的所有網絡請求接口,這樣就不會出現DataEngine大爆炸,像我們的項目有300多個接口,拆分后有十幾個DataEngine,如果使用離散型API設計,那畫面太美我不敢看??

3.BaseEngine提供取消操作

每個接口生成一個BaseEngine實例,持有Client返回的requestID,所以就可以做取消操作,簡單的使用場景

  1. #import "ViewController.h" 
  2. #import "SearchDataEngine.h" 
  3. @interface ViewController () 
  4. @property (nonatomic, strong) YABaseDataEngine *searchDataEngine; 
  5. @end 
  6. @implementation ViewController 
  7. - (void)viewDidLoad { 
  8.     [super viewDidLoad]; 
  9.     // Do any additional setup after loading the view, typically from a nib. 
  10.     [self.searchDataEngine cancelRequest]; 
  11.     self.searchDataEngine = [SearchDataEngine control:self searchKey:@"關鍵字" complete:^(id data, NSError *error) { 
  12.     if (error) { 
  13.         NSLog(@"%@",error.localizedDescription); 
  14.     } else { 
  15.         NSLog(@"%@",data); 
  16.     } 
  17.     }]; 
  18. @end 

4.返回的YABaseDataEngine實例ViewController不是必須持有的,當有需要取消操作的時候再去持有就行了

這樣的設計就集成了集約型和離散型的有點,又解決了集約型和離散型的缺點

網絡請求怎么自動取消

當一個頁面的請求正在天上飛的時候,用戶等了好久不耐煩了,小手點了個back,然后ViewController被pop被回收。此時請求的著陸點就沒了。這是很危險的情況,著陸點要是沒了,就很容易crash的。

casa大神說在BaseDataEngine的dealloc里面做取消網絡請求操作,我也是這樣想的,但是casa大神說要把BaseDataEngine綁定給ViewController,當ViewController銷毀時BaseDataEngine也就跟著銷毀了,這樣我也是同意的,但是要讓我不管什么情況都要給ViewController添加BaseDataEngine變量來保存BaseDataEngine這是我萬萬不能接受的,而且有的ViewController會發起兩三種網絡請求,難道要我添加兩三個變量?代碼入侵太大,所以這里偷偷使用了一個巧,使用了runtime,給ViewController添加一個字典,來保存requestID和BaseDataEngine,這樣對于ViewController來說就不是必須要寫變量來持有BaseDataEngine了,所以就出現了上面的DataEngine里面要把control傳遞進來的樣子

在發起請求的時候進行綁定

  1. [control.networkingAutoCancelRequests setEngine:self requestID:self.requestID]; 

在請求完成的時候進行刪除

  1. [weakControl.networkingAutoCancelRequests removeEngineWithRequestID:engine.requestID]; 

公司上個大神的做法

雖然使用control的做法很方便,但是如果說要把現在已有的接口都添加一個control字段的工作量也是很大的,如果已有的接口是使用字典傳遞給DataEngine的,這里給大家一個公司上個大神的做法,使用內存地址,將內存地址添加到字典中去,用內存地址做key綁定,也是可以的。如果是像我這樣直接把關鍵參數傳遞過來的,不是用的字典,就不行了。

  1. NSString *memoryAddress = [NSString stringWithFormat:@"%p", self]; 

網絡層錯誤處理

說實話,錯誤處理該放在按個地方我也是糾結了好久,也和公司同事討論了好久,最終定下來了一套方案,僅供大家參考。

我們將錯誤處理分為兩個步驟,一個是錯誤解析,一個是錯誤的UI展示

大家可以看到我設計的接口返回數據是標準的id data, NSError *error,所以我的想法是Client就把error處理好,不管你是網絡超時錯誤也好,或者是數據格式不正確也好,都error解析完整,把code錯誤碼定義好,上層根據需要通過code來做具體的UI展示,因為有的界面的錯誤需要用戶的點擊確認,有的頁面的錯誤只是一閃而過的提示框,把error交給BaseEngine或者DataEngine來處理errorUI,所以我定義了一套errorUI的枚舉,當BaseEngine拿到error的時候就去做錯誤的展示

總結

架構的設計更多的是思路,我希望的是大家能通過我們提供的思路取其精華去其糟粕,總會設計會最適合你的項目的架構的

另外我的這套設計存在的爭議的點可能會有很多,有一部分我已經在文中提到了,如果大家有什么其他的想法我們再討論

1.關于block

對于block和delegate的選擇,我更傾向于block,只有一個原因,因為block的結構更方便閱讀,這一個優點我覺得足以秒殺他所有的缺點,可以這樣說,我現在的項目基本上很少用到delegate了。

什么時候自定義delegate?就是當你的不同時期的回調超過2次的時候(不包含2次),3次回調就看情況了,如果要處理的邏輯比較少就使用block,多的話就使用delegat,一旦超過3次,基本上就不會考慮block,希望大家也不要對block存在偏見,延遲生命周期什么的都是可以解決的,一個宏定義就解決了,順便給出strongSelf,如果這么方便的宏都不愿意使用,那是真的不適合用block了,誰也救不了你

  1. #define WEAKSELF typeof(self) __weak weakSelf = self; 
  2. #define STRONGSELF typeof(weakSelf) __strong strongSelf = weakSelf; 

2.交付什么樣的數據給ViewController?是model還是data

這個有什么好爭議的嗎?有DataEngine在,交付什么樣的數據還不是你說了算。

底層的BaseEngine和Client當然還是data比較合適,到了DataEngine層,你想交付什么樣的數據就交什么樣的數據,可以看業務層的需求,有的接口根本就不包含model,你非要統一所有的接口都返回model這不是扯淡嗎,所以我的建議是根據接口的實際情況來,統一規范,我們的設計因為有些接口是不需要model的,以后就統一返回data

3.優化

我的這套設計只是基本思路,還有很多優化的點,我知道。

這部分就是各顯神通的地方了,不是我藏私,而是現在的項目對于網絡層沒有太多的優化點,所以我也沒做太多,做的部分敏感代碼太多,實在是沒辦法拆出來,不過可以告訴大家一個小的優化點,errorUI的處理可以考慮做成隊列,比如需要用戶點擊確定的彈出框,而且內容都是一樣的,放在隊列里面只顯示一次就好

4.為什么業務層沒有使用RequestDataModel

model就是對象,下層主要是用來做數據傳遞的,用model沒有問題;而向上到業務層的時候,更多的理念是方法的調用,而且方法的定義更有針對性,這個時候用model就不合適了。就好像超市一樣,進貨的時候是使用集裝箱拉貨的,所有的東西都裝在一起,當到柜臺的時候就會一個個的分類擺好。

責任編輯:倪明 來源: Yasin的簡書
相關推薦

2014-09-02 10:54:20

架構設計權限系統

2017-03-21 17:04:05

Android客戶端架構設計

2012-06-07 10:22:48

架構設計邏輯層物理層

2012-06-07 10:53:08

架構設計數據訪問層設計原則

2012-05-30 09:43:45

業務邏輯層

2012-06-07 10:35:40

架構設計業務邏輯Java

2020-11-22 08:10:05

架構運維技術

2009-01-15 09:43:51

Web架構設計緩存

2021-07-21 16:30:38

iOSAPP架構

2017-11-24 08:32:04

架構設計存儲

2024-11-27 13:01:22

應用層領域層對接層

2012-06-07 10:25:35

架構設計服務層軟件設計

2010-09-17 08:50:30

Visual Stud

2013-09-02 13:52:30

網絡基礎架構基礎架構設計

2021-01-11 10:19:51

安全架構

2012-05-24 10:19:42

QQ瀏覽器Android設計分享

2024-01-25 08:11:31

2013-05-27 10:58:28

Tumblr架構設計雅虎收購

2016-03-25 09:57:09

統一監控報警平臺運維

2015-01-27 15:25:53

MVVM
點贊
收藏

51CTO技術棧公眾號

国产爆乳无码一区二区麻豆| 国产免费一区二区三区香蕉精| 久久久男人的天堂| 中文在线8资源库| 国产精品卡一卡二| 国产精品一区二区免费看| 亚洲图片在线视频| 久久久久久久久丰满| 亚洲国产精品久久久| 国产免费又粗又猛又爽| 男女羞羞视频在线观看| 国产欧美日本一区二区三区| 97视频中文字幕| 国产亚洲欧美日韩高清| 欧美日韩国产欧| 国产亚洲综合久久| 亚洲色图欧美日韩| 国产成人亚洲一区二区三区 | 1024在线看片| 国产精品色在线网站| 在线亚洲欧美专区二区| 美女扒开大腿让男人桶| 日本不卡不卡| 国产色婷婷亚洲99精品小说| 国产精品免费在线| 国产露脸国语对白在线| 丝袜美腿亚洲综合| 97精品久久久中文字幕免费| 亚洲天堂黄色片| 成人激情电影在线| 亚洲欧洲高清在线| 国产精品久久久免费观看| 精品国产18久久久久久二百| 欧美亚洲动漫精品| 中文字幕欧美人妻精品一区| 日本乱码一区二区三区不卡| 亚洲午夜一区二区| 亚洲啊啊啊啊啊| 成人影院在线观看| 亚洲欧美中日韩| 视频一区视频二区视频三区视频四区国产| 天天干天天草天天射| 国产经典欧美精品| 亚洲最大福利视频网| 97人妻精品一区二区三区软件 | 亚洲精品ww久久久久久p站| 日韩高清国产精品| 蜜芽tv福利在线视频| 91在线视频18| 精品麻豆av| 天堂av中文字幕| 成人高清视频在线| 国产伦精品一区二区| 亚洲免费一级片| 国产不卡在线播放| 国产精品播放| 日本黄视频在线观看| 不卡视频免费播放| 激情伦成人综合小说| 天堂在线观看视频| 91美女精品福利| 欧美日韩在线一区二区三区| 日韩美女一级视频| 国产日韩欧美a| 天天爽天天狠久久久| √天堂资源地址在线官网| 国产精品欧美一区二区三区| 中文视频一区视频二区视频三区| 欧美成人hd| 亚洲免费资源在线播放| 日韩在线视频在线| 久草免费在线视频| 在线欧美日韩国产| 中文字幕在线视频一区二区三区 | 日日摸夜夜添夜夜添国产精品| 国产ts一区二区| 一区二区三区在线免费观看视频 | 毛片免费不卡| 亚洲最新视频在线播放| 日韩欧美视频网站| 成人国产网站| 日韩欧美国产综合在线一区二区三区| 亚洲美女高潮久久久| 亚州av一区| www.欧美免费| 日本熟妇毛茸茸丰满| 鲁大师影院一区二区三区| 国产伦精品一区二区三区精品视频| 91亚洲视频在线观看| 成人免费精品视频| 日韩一本精品| 麻豆av在线免费观看| 色综合天天狠狠| 三级av免费看| 亚洲欧美tv| 欧美插天视频在线播放| 91久久国产视频| 久久99精品久久久久久国产越南| 成人一区二区三区四区| 国产无套粉嫩白浆在线2022年 | 久久最新免费视频| 少妇视频一区| 欧美一区二区三区免费观看视频| 日韩免费高清一区二区| 91蜜臀精品国产自偷在线| 久久久久久久久久久久av| 无码人妻精品一区二区蜜桃色欲| 精品亚洲国产成人av制服丝袜 | 日韩精品第一区| 97热在线精品视频在线观看| 一区二区三区亚洲视频| 99国产精品久久久久| 中国一级黄色录像| 日韩一级二级| 亚洲国产日韩欧美在线99| 国产精品久久久免费看| 久久中文欧美| 国新精品乱码一区二区三区18| 91大神xh98hx在线播放| 日韩欧美精品网站| www.黄色网| 国产精品x453.com| 国产精品96久久久久久又黄又硬| 国产激情视频在线播放| 国产精品美女久久久久久久久 | 在线a欧美视频| 久久狠狠高潮亚洲精品| 国产不卡视频在线播放| 四虎免费在线观看视频| 日韩中文视频| 亚洲最新av在线网站| www.欧美色| 91网站黄www| 亚欧无线一线二线三线区别| 国产午夜亚洲精品一级在线| 日韩网站免费观看| 中文字幕一区二区三区四区视频 | 日韩性xxxx爱| 国产精品欧美综合| 国产人久久人人人人爽| 国产裸体舞一区二区三区| 丝袜连裤袜欧美激情日韩| 久久免费视频网| 蜜臀av中文字幕| 亚洲国产成人av| 69亚洲乱人伦| 亚洲精品乱码久久久久久蜜桃麻豆| 99久久伊人精品影院| 先锋成人av| 日韩你懂的在线播放| 国产a免费视频| 国产精品一区二区免费不卡| 波多野结衣与黑人| 99re91这里只有精品| 韩国美女主播一区| www.97超碰| 性做久久久久久久免费看| 69xxx免费视频| 日韩亚洲精品在线| 欧美精品中文字幕一区二区| 男人皇宫亚洲男人2020| 国产亚洲人成a一在线v站| 中文字幕在线播出| 亚洲欧美视频在线观看| 日本一区二区免费视频| 国产欧美午夜| 天堂精品一区二区三区| 免费一区二区三区在线视频| 欧美激情视频一区二区三区不卡| 日韩中文字幕观看| 在线一区二区三区| 国产一区二区播放| 不卡大黄网站免费看| 国产福利一区视频| 91精品国产91久久久久久密臀 | 青青久久aⅴ北条麻妃| 福利片在线看| 日韩午夜在线观看视频| 午夜精品久久久久久久久久久久久蜜桃| 久久久亚洲欧洲日产国码αv| 69久久久久久| 午夜欧美精品久久久久久久| 麻豆精品视频| 99er精品视频| 2020欧美日韩在线视频| 蜜桃视频网站在线| 亚洲精品国产精品国自产观看浪潮| 无码免费一区二区三区| 亚洲乱码国产乱码精品精的特点 | 亚洲盗摄视频| 成人写真视频福利网| а√天堂中文在线资源8| 伊人成人开心激情综合网| www.日韩在线观看| 欧美亚洲尤物久久| 久久一区二区三| 欧美韩国日本一区| 日本少妇xxxx| 精品亚洲免费视频| 成人黄色一区二区| 黄色亚洲精品| 伊人久久av导航| 亚洲传媒在线| 99久久精品久久久久久ai换脸| 成人看片在线观看| 97精品欧美一区二区三区| 男人天堂手机在线| 国产一区二区三区直播精品电影| 后进极品白嫩翘臀在线视频| 欧美日韩中文精品| 欧美a视频在线观看| 亚洲亚洲人成综合网络| 日韩欧美在线视频播放| 久久―日本道色综合久久| 日本女人性视频| 老鸭窝一区二区久久精品| 亚洲国产精品久久久久婷蜜芽| 最新精品国产| 中文视频一区视频二区视频三区| 狠狠做六月爱婷婷综合aⅴ| 国产一区福利视频| 日韩高清一区| 91九色精品视频| 国产精品久久久久77777丨| 奇米影视亚洲狠狠色| 亚洲精品久久久中文字幕| 亚洲精品进入| 国产欧美一区二区视频| 精品一区二区三区中文字幕在线| 国产精品网红福利| 亚洲不卡系列| 国产精品福利网| 亚洲www.| 日韩女优人人人人射在线视频| 黄色18在线观看| 韩国美女主播一区| 毛片电影在线| 97成人精品区在线播放| 波多野一区二区| 国自产精品手机在线观看视频| 金瓶狂野欧美性猛交xxxx| 欧美老少配视频| 日本精品600av| 欧美国产日本高清在线| 性欧美高清come| 欧美大片第1页| 麻豆av在线免费观看| 国精产品一区一区三区有限在线| 伦理av在线| 668精品在线视频| 欧美伦理91| 日韩女优在线播放| 国产精品第一| 亚洲影院色无极综合| 亚洲一区二区三区中文字幕在线观看| 亚洲字幕在线观看| 懂色av一区二区| 欧美日韩亚洲免费| 四季av在线一区二区三区 | 国产毛片在线| 中文字幕精品一区久久久久| 蜜桃视频在线观看免费视频网站www| 久久久国产在线视频| 欧美人与牲禽动交com| 午夜精品久久久久久久99热| free性护士videos欧美| 日本一本a高清免费不卡| 成人在线黄色| 91免费欧美精品| 国产一区福利| 欧美aaaaa喷水| 国产精品久久久久久麻豆一区软件| 最近中文字幕免费mv| 精品1区2区3区4区| 亚洲中文字幕无码不卡电影| 久久91精品久久久久久秒播| 四川一级毛毛片| 91蜜桃免费观看视频| 精品在线观看一区| 亚洲国产精品人人做人人爽| 免费污污视频在线观看| 制服丝袜国产精品| 婷婷在线免费视频| 中文字幕精品av| 暖暖在线中文免费日本| 国产精品高精视频免费| 一区二区亚洲视频| 日韩av影视| 国产精品vip| 999在线免费视频| 福利一区福利二区| 99国产精品免费| 午夜激情一区二区三区| 中文字幕在线一| 亚洲精品之草原avav久久| 国产精品刘玥久久一区| 欧美在线亚洲在线| 日韩精品一区二区三区中文在线 | 欧美午夜电影一区二区三区| 国产最新精品视频| va天堂va亚洲va影视| 你懂的视频在线一区二区| 亚洲欧美综合国产精品一区| 国产精品人人妻人人爽人人牛| 国产老肥熟一区二区三区| 日本成人免费视频| 亚洲va韩国va欧美va| 97人妻精品一区二区三区| 亚洲欧美国产一区二区三区| 婷婷av在线| 成人黄在线观看| 国产一区二区亚洲| 免费无码不卡视频在线观看| 国产成人午夜99999| 国产精品综合激情| 色综合天天综合给合国产| 天天摸天天干天天操| 欧美日本亚洲视频| 高清在线一区二区| 亚洲一区三区在线观看| 久久久国产亚洲精品| 9.1成人看片| 精品久久久久久久久中文字幕| av网站在线免费看| 久久激情视频免费观看| 91国拍精品国产粉嫩亚洲一区| 久久99国产精品| 亚洲高清资源| 国产大学生av| 一区二区三区.www| 精品久久久无码中文字幕| 久久精品国产一区二区三区| 久久人体av| 亚洲视频小说| 久久国产精品99久久久久久老狼| 强伦人妻一区二区三区| 欧美性色xo影院| 青青草在线免费观看| 91精品国产一区| 蜜桃一区二区三区| 日本www高清视频| 久久女同互慰一区二区三区| www欧美在线| 亚洲欧美日韩国产中文专区| 亚洲欧洲高清| 欧美性大战久久久久| 久久蜜桃精品| 久久视频精品在线观看| 欧美特级限制片免费在线观看| 成人影视在线播放| 国产精品视频网址| 久久免费精品视频在这里| 欧美一级xxxx| 樱花草国产18久久久久| 午夜久久久久久久久久| 97视频免费在线看| 中文字幕精品影院| 一级在线免费视频| 日韩毛片一二三区| 精品国精品国产自在久不卡| 国语自产在线不卡| 免费成人结看片| 思思久久精品视频| 亚洲精品免费一二三区| 天堂av资源网| 国产精品久久久久av免费| 亚洲精品国产首次亮相| 亚洲黄色小说在线观看| 欧美日韩在线另类| www.视频在线.com| 99九九视频| 老鸭窝91久久精品色噜噜导演| 成人无码av片在线观看| 欧美人妖巨大在线| 国产丝袜在线观看视频| 快播日韩欧美| 国产一区不卡精品| 国产成人无码精品| 最近日韩中文字幕中文| 2021年精品国产福利在线| 日韩毛片在线免费看| 亚洲人亚洲人成电影网站色| 无码精品人妻一区二区| 国产精品女主播视频| 亚洲视频中文| 免费成人深夜蜜桃视频| 欧美精品一区二区久久婷婷| 日韩免费小视频| 隔壁人妻偷人bd中字| 久久久久久久久久久99999| 91精品国产乱码久久| 26uuu国产精品视频| 香蕉久久网站| 加勒比综合在线| 日韩精品在线一区| 亚洲电影有码| 男人日女人逼逼| 亚洲欧美韩国综合色| 黄色小视频在线免费观看| dy888夜精品国产专区|