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

用Swift編寫網絡層:面向協議方式

移動開發
在這篇文章中我們會看到怎樣實現用純swift編寫網絡層,而不依靠任何第三方庫。讓我們快去看看吧。相信看完之后我們的代碼能夠做到。

用Swift編寫網絡層:面向協議方式

在這篇文章中我們會看到怎樣實現用純swift編寫網絡層,而不依靠任何第三方庫。讓我們快去看看吧。相信看完之后我們的代碼能夠做到:

  • 面向協議
  • 易用
  • 容易實現
  • 類型安全
  • 用枚舉(enums)來配置終端(endPoints)

下面是一個最終我們網絡層的示例

 

2.png
這個項目的最終目標

通過輸入router.request(. 借助枚舉的力量,我們可以看到所有有效的終端和我們請求的參數)

首先,一些結構

創建任何東西之前,有個結構都是很重要的,這樣后面我們就容易找到需要的東西。我堅定相信文件夾結構對軟件架構至關重要。為了讓我們的文件組織有序,讓我們提前建立好所有的組,我會標記好每一個文件該放的位置。這是一個項目結構總覽。(請注意這里的名字僅僅是建議,你可以按你喜好給你的類和組命名)

 

3.png
項目文件夾結構

終端類型(EndPointType)協議

我們要做的***件事情就是定義我們的終端類型協議。這個協議要包含用于配置終端的所有信息。什么是終端?本質上來講它是一個包含各種組件比如頭文件(headers),查詢參數(query parameters),體參數(body parameters)的URL請求(URLRequest)。終端類型協議是我們網絡層實現的基石。我們建一個文件,并命名EndPointType,把它放到服務組中(不是終端組,后面我們分清楚的)。

 

4.png
終端類型協議

HTTP協議

為了創建一個完整的終端,我的終端類型協議里有很多HTTP協議。讓我們看看這些協議需要什么。

HTTP方法

創建一個名為HTTPMethod的文件并把它放在服務組中。這個枚舉會用于設置我們請求用的HTTP方法。

 

5.png
HTTPMethod枚舉

HTTP任務

創建一個名為HTTPTask的文件并把它放在服務組中。HTTPTask用于為一個特定的終端配置參數,你可以添加適當數量的案例(cases)到你的網絡層請求中。我會按下圖建立我的請求,它只包含3個案例

 

6.png
HTTPTask枚舉

在下一章我們會討論參數和如何處理參數的編碼。

HTTP頭文件

HTTPHeaders是一個字典的別名(typealias)。你可以在你HTTPTask文件的開頭創建它。

  1. public typealias HTTPHeaders = [String:String] 

參數與編碼

創建一個名為ParameterEncoding的文件并把它放在編碼組中。我們首先要定義一個參數的別名,通過它我們可以讓代碼更干凈簡潔。

  1. public typealias Parameters = [String:Any

之后用一個靜態函數編碼定義一個協議參數編碼器(ParameterEncoder)。這種編碼方式含有2個參數,一個inout URLRequest和Parameters。(為了防止混淆,后面我會把函數參數稱為參量)。INOUT是一個swift關鍵詞,用于把一個參量定義為引用參量。通常變量作為值類型傳送給函數。通過在參量的開頭加上inout,我們把它定義為引用類型。要學更多關于雙向參量,你可以點擊這里。參數編碼器協議會通過JSONParameterEncoder和URLPameterEncoder實現。

 

  1. public protocol ParameterEncoder { 
  2.  static func encode(urlRequest: inout URLRequest, with parameters: Parameters) throws 

參數編碼器執行編碼參數的函數,這個方法會失敗,返回一個錯誤,因而我們需要處理它。

能夠返回一個自定的錯誤提示比標準錯誤提示會更有價值。我總是花很多時間去分析Xcode給的一些錯誤提示。有了自定的錯誤提示你就可以定義屬于自己的錯誤信息,就能清楚知道錯誤到底來自哪里。為了做到這些,我創建了一個繼承自Error的枚舉。

 

7.png
NetworkError枚舉

URL參數編碼器

創建一個名為URLParameterEncoder的文件并把它放在編碼組中。

 

8.png
URL參數編碼器代碼

上面的代碼含有一些參數,它可以將他們變成URL參數來安全傳遞。你要知道一些字符在URL中一些字符是禁用的。參數也被‘&’標記分開,我們需要考慮到所有這些。如果之前沒有設置,我們還要為請求添加合適的頭文件。

這個示例代碼是使用單元測試時應該考慮到的。如果URL沒有正確建立,我們就會有很多不必要的錯誤。如果你在使用一個開放API,你一定不希望自己的請求配額被一堆錯誤測試用完。如果你想學更多關于單元測試內容,你可以看S.T.Huang的這篇文章。

JSON參數編碼器

創建一個名為JSONParameterEncoder的文件,也把它放在編碼組中。

 

9.png
JSON參數編碼器代碼

類似URL參數編碼器,不過這里是為JSON編碼參數,同樣要添加合適的頭文件。

網絡路由器

創建一個名為NetworkRouter的文件并把它放在服務組中。我們從為一個完成部分(completion)定義別名開始。

  1. public typealias NetworkRouterCompletion = (_ data: Data?,_ response: URLResponse?,_ error: Error?)->() 

之后我們定義一個協議網絡路由器

 

10.png
NetworkRouter代碼

一個網絡路由器有一個用于產生請求的終端,一旦請求產生,它會傳遞對完成部分的應答。我加入了一個取消函數,有它當然好,但不是一定要用到。這個函數可以在一個請求存在周期的任意時刻調用并取消它。如果你的應用有上傳或下載任務,這會很有用。為了讓我們的路由器能處理任何終端類型,我們這里使用了關聯類型。如果不用關聯類型,路由器就不得不有一個具體的終端類型。想對關聯類型了解更多,建議看NatashaTheRobot的這篇文章。

路由器

創建一個名為Router的文件并把它放在服務組中。我們聲明一個URLSessionTask類型的私有變量任務。這個任務本質上是整個工作要做的。我們讓這個變量私有化,因為我們不想任何這個類之外的任何東西會調整我們的任務。

 

11.png
Router方法存根

請求

這里我們使用共享的會話管理(session)創建URLSession,這是創建URLSession最簡單的辦法,但請記住這不是***的方法。要實現對URLSession更復雜的配置,則要用能夠改變會話管理表現的配置。想了解更多,我推薦讀一讀這篇文章。

這里我們通過調用buildRequest生成我們的請求,并給它一個終端作為路徑。這個buildRequest的調用被限制在一個do-try-catch區塊,因為我們的編碼器可能會報出錯誤。我們僅僅把所有應答,數據和錯誤傳送給完成部分。

 

12.png
Request方法代碼

建立請求

在Router中創建一個名為buildRequest的私有函數,這個函數負責我們網絡層中一切重要工作。本質上就是把EndPointType轉化為URLRequest。一旦我們的終端生成請求,我們可以把它傳遞給會話管理。這里有很多工作要做,所以我們將會分別看看每個方法。讓我們分解buildRequest方法:

我們舉了一個URLRequest類型的變量請求的例子。把我們的基礎URL給它,并附上我們要用到的路徑。

我們設定這請求的httpMethod和我們終端的一致。

考慮到我們的編碼器會報告錯誤,我們創建一個do-try-catch區塊。只要創建一個大的do-try-catch區塊,我們就不需要為每次嘗試分別建一個。

開啟route.task

根據任務,調用合適的編碼器。

 

13.png
buildRequest方法代碼.

配置參數

在Router中創建一個名為configureParameters的函數

 

14.png
configureParameters方法的實現

這個函數負責為我們的參數編碼。因為我們的API要求所有的bodyParameters都是JSON,并且URLParameters是URL編碼的,我們把合適的參數傳遞給設計好的編碼器。如果你正在用一個有多種編碼方式的API,我建議修改HTTPTask來使用編碼器枚舉。這個枚舉需要包含所有你需要的不同類型編碼器。之后在configureParameters添加一個關于你編碼枚舉的附加參量。開啟這個枚舉,合適地為參數編碼。

添加附加頭文件

在Router中創建一個名為addAdditionalHeaders的函數

 

15.png
addAdditionalHeaders方法的實現

添加所有附加頭文件,讓它們成為請求頭文件的一部分。

取消

取消函數的實現是這樣的:

 

16.png
cancel方法的實現

實踐

現在讓我們用一個實際例子看看我們建立的網絡層。我們將從TheMovieDB獲取一些電影數據到我們的應用。

電影終端(MovieEndPoint)

電影終端與我們在Getting Started with Moya中提到的目標類型很相似。與實現Moya中目標類型不同的是這里我們實現我們自己的終端類型。把這個文件放在終端組中。

 

  1. import Foundation   
  2.   
  3. enum NetworkEnvironment { 
  4.     case qa 
  5.     case production 
  6.     case staging 
  7.   
  8. public enum MovieApi { 
  9.     case recommended(id:Int
  10.     case popular(page:Int
  11.     case newMovies(page:Int
  12.     case video(id:Int
  13.   
  14. extension MovieApi: EndPointType { 
  15.      
  16.     var environmentBaseURL : String { 
  17.         switch NetworkManager.environment { 
  18.         case .production: return "https://api.themoviedb.org/3/movie/" 
  19.         case .qa: return "https://qa.themoviedb.org/3/movie/" 
  20.         case .staging: return "https://staging.themoviedb.org/3/movie/" 
  21.         } 
  22.     } 
  23.       
  24.     var baseURL: URL { 
  25.         guard let url = URL(string: environmentBaseURL) else { fatalError("baseURL could not be configured.")} 
  26.         return url 
  27.     } 
  28.      
  29.     var path: String { 
  30.         switch self { 
  31.         case .recommended(let id): 
  32.             return "\(id)/recommendations" 
  33.         case .popular: 
  34.             return "popular" 
  35.         case .newMovies: 
  36.             return "now_playing" 
  37.         case .video(let id): 
  38.             return "\(id)/videos" 
  39.         } 
  40.     } 
  41.       
  42.     var httpMethod: HTTPMethod { 
  43.         return .get 
  44.     } 
  45.       
  46.     var task: HTTPTask { 
  47.         switch self { 
  48.         case .newMovies(let page): 
  49.             return .requestParameters(bodyParameters: nil, 
  50.                                       urlParameters: ["page":page, 
  51.                                                       "api_key":NetworkManager.MovieAPIKey]) 
  52.         default
  53.             return .request 
  54.         } 
  55.     } 
  56.       
  57.     var headers: HTTPHeaders? { 
  58.         return nil 
  59.     } 

終端類型

電影模式(MovieModel)

因為對TheMovieDB的回應同樣是JSON,我們的電影模式也不會改變。我們用可解碼協議來把JSON轉化為我們的模式。把這個文件放在模式組中。

 

  1. import Foundation 
  2.   
  3. struct MovieApiResponse { 
  4.     let page: Int 
  5.     let numberOfResults: Int 
  6.     let numberOfPages: Int 
  7.     let movies: [Movie] 
  8.   
  9. extension MovieApiResponse: Decodable { 
  10.      
  11.     private enum MovieApiResponseCodingKeys: String, CodingKey { 
  12.         case page 
  13.         case numberOfResults = "total_results" 
  14.         case numberOfPages = "total_pages" 
  15.         case movies = "results" 
  16.     } 
  17.      
  18.     init(from decoder: Decoder) throws { 
  19.         let container = try decoder.container(keyedBy: MovieApiResponseCodingKeys.self) 
  20.           
  21.         page = try container.decode(Int.self, forKey: .page) 
  22.         numberOfResults = try container.decode(Int.self, forKey: .numberOfResults) 
  23.         numberOfPages = try container.decode(Int.self, forKey: .numberOfPages) 
  24.         movies = try container.decode([Movie].self, forKey: .movies) 
  25.           
  26.     } 
  27.   
  28.   
  29. struct Movie { 
  30.     let id: Int 
  31.     let posterPath: String 
  32.     let backdrop: String 
  33.     let title: String 
  34.     let releaseDate: String 
  35.     let rating: Double 
  36.     let overview: String 
  37.   
  38. extension Movie: Decodable { 
  39.      
  40.     enum MovieCodingKeys: String, CodingKey { 
  41.         case id 
  42.         case posterPath = "poster_path" 
  43.         case backdrop = "backdrop_path" 
  44.         case title 
  45.         case releaseDate = "release_date" 
  46.         case rating = "vote_average" 
  47.         case overview 
  48.     } 
  49.       
  50.      
  51.     init(from decoder: Decoder) throws { 
  52.         let movieContainer = try decoder.container(keyedBy: MovieCodingKeys.self) 
  53.          
  54.         id = try movieContainer.decode(Int.self, forKey: .id) 
  55.         posterPath = try movieContainer.decode(String.self, forKey: .posterPath) 
  56.         backdrop = try movieContainer.decode(String.self, forKey: .backdrop) 
  57.         title = try movieContainer.decode(String.self, forKey: .title) 
  58.         releaseDate = try movieContainer.decode(String.self, forKey: .releaseDate) 
  59.         rating = try movieContainer.decode(Double.self, forKey: .rating) 
  60.         overview = try movieContainer.decode(String.self, forKey: .overview) 
  61.     } 

電影模式

網絡管理員

創建一個名為NetworkManager的文件并把它放在管理員組中。

現在開始我們的網絡管理員將僅有2個靜態屬性:你的API密碼和網絡環境(引用MovieEndPoint)。網絡管理員也有一個類型為MovieApi的Router。

 

17.png
NetworkManager代碼

網絡響應

在NetworkManager中創建一個名為NetworkResponse的枚舉。

 

18.png
NetworkResponse枚舉

我們將用這個枚舉處理來自API的響應,并顯示相應的信息。

結果

在NetworkManager中創建一個枚舉Result。

 

19.png
Result枚舉

一個結果枚舉可以用在很多不同事情上,非常有用。我們根據結果確定我們對API的調用是成功還是失敗。如果失敗了,我們會返回一個錯誤信息并說明原因。想了解更多面向結果的編程,你可以看這篇對話。

處理網絡響應

創建一個名為handleNetworkResponse的函數,這個函數有一個參量,即HTTPResponse,并返回一個Result.

 

20.png

這里我們開啟HTTPResponse的狀態碼,狀態碼是一個能告訴我們響應狀態的HTTP協議?;旧?00-299之間都是成功。

產生調用

現在我們已經為我們的網絡層打下雄厚的基礎。是時候開始調用了。

我們將會從API獲取一個新電影列表。創建一個名為getNewMovies的函數。

 

21.png
getNewMovies方法的實現

讓我們分解這個方法的每一步

  1. 我們定義getNewMovies方法含有2個參量:一個頁碼和一個能返回電影數組或錯誤信息的完成部分(completion)。
  2. 我們調用我們的路由器,輸入頁碼并在一個閉包(closure)內處理這個完成部分。
  3. 如果沒有網絡或者出于一些原因無法調用API,URLSession會返回錯誤。請注意這并不是API的失敗。這種失敗多是客服端的,很可能是因為網絡連接不好。
  4. 我們需要把我們的響應轉變為一個HTTPURLResponse,因為我們需要訪問狀態碼屬性。
  5. 我們聲明一個從handleNetworkResponse方法得到的結果,之后在switch-case區塊檢查這個結果。
  6. 成功意味著我們成功地和API聯系,并得到一個適當的響應。之后我們檢查這個響應是否攜帶數據。如果沒有數據我們就用返回語句退出這個方法。
  7. 如果攜帶有數據,我們需要把數據編碼成我們的模式,之后我們把編碼好的電影傳遞給完成部分。
  8. 如果結果是失敗,我們就把錯誤傳遞給完成部分。

這就完成了,這就是我們不依賴Cocoapods和第三方庫的純Swift網絡層。想要測試api請求能否獲取電影,就創建一個帶有Network Manager 的viewController之后在管理員調用getNewMovies。

 

  1. class MainViewController: UIViewController { 
  2.      
  3.     var networkManager: NetworkManager! 
  4.       
  5.     init(networkManager: NetworkManager) { 
  6.         super.init(nibName: nil, bundle: nil) 
  7.         self.networkManager = networkManager 
  8.     } 
  9.      
  10.     required init?(coder aDecoder: NSCoder) { 
  11.         fatalError("init(coder:) has not been implemented"
  12.     } 
  13.       
  14.     override func viewDidLoad() { 
  15.         super.viewDidLoad() 
  16.         view.backgroundColor = .green 
  17.         networkManager.getNewMovies(page: 1) { movies, error in 
  18.             if let error = error { 
  19.                 print(error) 
  20.             } 
  21.             if let movies = movies { 
  22.                 print(movies) 
  23.             } 
  24.         } 
  25.     } 

MainViewControoler的示例

迂回網絡(DETOUR- NETWORK)記錄器

我最喜歡的Moya特性之一就是網絡記錄器。它使得調試變得更容易,并且通過記錄所有網絡通信可以看到關于請求和響應發生了什么。我決定實現這個網絡層時候就想要有這個特性了。創建一個名為NetworkLogger的文件并把它放在服務組中。我已經實現了一個記錄對控制臺請求的代碼。我不會展示我們應該把代碼放到代碼層中的哪里。這是對你的一個挑戰,創建一個記錄控制臺響應的函數,并在我們的架構中找到合適的位置放置它們。

提示:靜態函數記錄(響應:URLResponse)

小技巧

你在Xcode中遇到過不理解的占位符嗎?比如讓我們看看剛剛為了實現Router寫的代碼

 

22.png

NetworkRouterCompletion是我們實現的。即使我們實現了它,有時候也很難記清它是哪種類型,我們該怎么用它。我們喜歡的Xcode有解決辦法。只要在占位符上雙擊,Xcode就會告訴你。

 

23.png

結論

我們有了一個簡單好用,面向協議,還可以自己定制的網絡層。我們能完全控制它的功能,完全理解它的機制。通過進行這個練習,我可以說我本人學到不少新事情。所以比起那些只需要裝一個庫就能完成的工作,我對這項工作更感到自豪。希望這篇文章能說明,用Swift創建你自己的網絡層并沒那么難。只要不做這樣的事情就行了:

 

[[228878]]

你可以在我的GitHub上找到源代碼,感謝閱讀。

責任編輯:未麗燕 來源: Malcolm Kumwenda
相關推薦

2015-08-04 08:56:14

swift子類

2015-09-15 10:40:41

Swift2.0MVVM

2018-07-23 15:55:28

協議自定義viewSwift

2014-06-27 10:04:55

網絡協議ipv4IP

2010-07-13 13:50:44

HART協議

2019-01-30 10:18:46

七層協議網絡通信

2019-04-14 22:33:52

網絡層協議VLAN虛擬局域網

2010-07-06 16:08:51

HART協議

2018-09-19 15:53:11

SwiftiOS系統

2022-07-30 23:41:53

面向過程面向對象面向協議編程

2010-09-09 16:48:50

七層網絡協議

2011-11-10 09:43:14

ZigBee協議棧網絡層

2010-06-09 10:28:20

2010-09-09 16:56:08

七層網絡協議

2021-03-11 13:56:13

協議Python網絡

2016-12-12 15:22:41

編程

2019-05-21 09:11:50

七層協議OSITCP

2010-06-10 14:20:23

2010-06-09 12:20:34

網絡通信協議層

2023-04-06 07:57:29

RPC服務網絡協議
點贊
收藏

51CTO技術棧公眾號

国产黄在线观看| 日韩精品一区二区av| 午夜不卡一区| 亚洲精品福利视频网站| 国产精品成人观看视频免费| 中文字幕在线观看视频网站| 欧美日韩激情在线一区二区三区| 欧美精品v国产精品v日韩精品 | 欧美在线色图| 日韩亚洲欧美在线| 欧美国产激情视频| 操你啦在线视频| 久久免费视频色| 亚洲一区二区三区毛片| 免费的毛片视频| 1024精品久久久久久久久| 精品欧美一区二区久久| 国产精品人人妻人人爽人人牛| 久久久久久久久免费视频| wwww国产精品欧美| 91在线免费看片| 又色又爽又黄无遮挡的免费视频| 亚洲人成免费| 欧美大奶子在线| 国产精品av久久久久久无| 国产ts一区| 欧美精品777| 成人毛片一区二区| 国产欧美久久久久久久久| 久久精品视频一区二区三区| 国产美女精品久久久| 最近中文在线观看| 亚洲综合精品| 性色av一区二区三区| 国产乱国产乱老熟300| 欧洲视频一区| 亚洲欧美综合v| 亚洲天堂av网站| 国产精品igao视频网网址不卡日韩| 日本黄色精品| 亚洲欧美日韩综合国产aⅴ| 久久精品影视伊人网| 亚洲码无人客一区二区三区| 国产香蕉精品| 欧美精品一区二区三区久久久| 天天做天天干天天操| 午夜精品久久久久久久久久蜜桃| 亚洲成人av免费| wwwjizzjizzcom| 成人影院www在线观看| 国产精品免费久久| 日韩精品一线二线三线| 久久99久久| 2021久久国产精品不只是精品| 国产成人精品自拍| 成人免费公开视频| 国产精品自在欧美一区| 91在线视频一区| 99热这里只有精品在线| 久久精品国产亚洲高清剧情介绍| 国产精品国产三级国产aⅴ9色| 色老头一区二区| 日韩电影在线一区| 国产精品午夜视频| 一区二区三区免费在线| 精品一区二区三区久久| 亚洲一区二区三区777| 国产黄色av片| 成人av在线一区二区三区| 黄色99视频| 理论视频在线| 国产精品美女久久福利网站| 久久久国产精华液999999| 菠萝菠萝蜜在线观看| 亚洲久草在线视频| 欧美综合在线播放| 久久久人成影片一区二区三区在哪下载| 一本久道久久综合中文字幕| 日本888xxxx| www久久久| 欧美精品一区二区三区在线播放 | 欧美xxxx18性欧美| 精品一区在线视频| 美女爽到呻吟久久久久| 国产在线高清精品| 午夜精品无码一区二区三区| 99热精品国产| 亚洲视频电影| 久久www人成免费看片中文| 欧美日韩在线看| 婷婷免费在线观看| 亚洲三级av| 亚洲天堂男人天堂女人天堂| 午夜激情福利电影| 亚洲国产高清一区| 国产精品视频yy9099| 亚洲AV无码一区二区三区少妇| 91视视频在线直接观看在线看网页在线看 | 精品人妻一区二区三区免费看| 免费精品视频在线| 国产v亚洲v天堂无码| av在线免费观看网| 亚洲国产你懂的| 狠狠躁狠狠躁视频专区| 爱爱精品视频| 国产亚洲欧美一区| 国产性70yerg老太| 蜜桃视频在线观看一区二区| 国产精选在线观看91| 在线视频91p| 精品国产鲁一鲁一区二区张丽| 中文字幕第88页| 日韩激情啪啪| 欧美日韩第一视频| 一级黄在线观看| 91蝌蚪porny| 国产av熟女一区二区三区| 素人啪啪色综合| 日韩av最新在线观看| 在线观看成人毛片| 奇米影视在线99精品| 激情五月综合色婷婷一区二区| 免费在线看黄| 91久久精品网| 在线免费播放av| 欧美色图麻豆| 91影视免费在线观看| 国产在线超碰| 欧美日韩色婷婷| 中文字幕制服丝袜| 亚洲国产一区二区在线观看| 国产精品av电影| 无码国产精品一区二区色情男同| 最新热久久免费视频| 热久久精品免费视频| 国产一区在线电影| 色综合色综合久久综合频道88| 在线免费看91| 中日韩av电影| 亚洲狼人综合干| 蜜桃一区二区三区| 欧美最猛黑人xxxx黑人猛叫黄| 亚洲av色香蕉一区二区三区| 亚洲天堂福利av| 午夜免费看毛片| 日韩在线中文| 国产乱肥老妇国产一区二 | 国产又大又黄的视频| 国产精品视频看| 午夜免费精品视频| 欧美一区2区| 国产精品国产亚洲伊人久久 | 性色av一区二区三区| 亚洲精品久久久久久无码色欲四季 | 都市激情久久综合| 日韩精品中文字幕在线不卡尤物| 亚洲xxxx3d动漫| 国产精品一区二区在线观看不卡 | 肉体视频在线| 日韩欧美区一区二| 伊人365影院| fc2成人免费人成在线观看播放| 成人免费a级片| 91综合精品国产丝袜长腿久久| 欧美国产激情18| 蜜桃av中文字幕| 亚洲观看高清完整版在线观看| 中文字幕欧美视频| 国内一区二区三区| 久久精品国产精品国产精品污 | 手机av在线不卡| 久久99精品国产麻豆婷婷| 久久久成人精品一区二区三区| 久久国产精品美女| 午夜精品久久久久久久99热浪潮 | 日韩中文字幕在线视频| 国产精品久久久久久久成人午夜| 亚洲日本在线天堂| 男人网站在线观看| 美女久久一区| 特级毛片在线免费观看| 中文字幕一区二区三区四区久久| 国内精品中文字幕| 国产51人人成人人人人爽色哟哟| 欧美日韩在线一区二区| 日韩欧美综合视频| 不卡av在线网| 亚洲综合av在线播放| 激情久久一区| 日本在线成人一区二区| 成人涩涩视频| 欧美激情在线狂野欧美精品| 亚洲欧洲综合在线| 欧美久久久久久蜜桃| 欧美激情一区二区视频| 91啪九色porn原创视频在线观看| 韩国视频一区二区三区| 欧美体内she精视频在线观看| 久久久久久草| av在线亚洲一区| 2019中文字幕在线免费观看| a√在线中文网新版址在线| 日韩免费看网站| 91黑人精品一区二区三区| 一区二区三区免费在线观看| 久久丫精品国产亚洲av不卡| 黄色精品一二区| av动漫在线看| 在线成人直播| 日韩免费av一区二区三区| 日韩一区二区三区色| 国产精品69av| aa视频在线观看| 久久激情视频久久| 五十路在线视频| 欧美一区永久视频免费观看| 99久久久久久久久| 亚洲成年人影院| 手机av在线看| 国产三级精品视频| 精品影片一区二区入口| 国产综合久久久久影院| 超碰影院在线观看| 亚洲激情精品| a级黄色片免费| 久久神马影院| 欧美国产一二三区| 欧美电影在线观看免费| 成人动漫在线观看视频| 欧美一区二区三区婷婷| 日韩免费高清在线观看| hd国产人妖ts另类视频| 色综合老司机第九色激情| 久操视频在线播放| 色妞欧美日韩在线| 国产中文字幕在线| 亚洲人成网站免费播放| 天堂在线中文资源| 精品国产制服丝袜高跟| av老司机久久| 7777精品伊人久久久大香线蕉超级流畅| 波多野结衣黄色| 91久久国产综合久久| 日韩精品在线观看免费| 亚洲mv在线观看| 国产一国产二国产三| 亚洲成人动漫在线观看| 久久精品国产亚洲av麻豆色欲| 一区二区三区在线观看国产| 国产免费一区二区三区四区| 中文字幕av一区二区三区高| 日本高清黄色片| 欧美国产精品专区| 快灬快灬一下爽蜜桃在线观看| 国产欧美日产一区| 国产在线免费av| 国产精品久久久久久久久快鸭 | 制服丝袜av在线| 成人久久视频在线观看| 中文字幕在线视频播放| 久久亚洲影视婷婷| 日本美女xxx| 中文字幕中文乱码欧美一区二区| 一级肉体全黄裸片| 国产精品久久久久精k8| 青青操在线视频观看| 亚洲精品国产一区二区三区四区在线| 天天看片中文字幕| 亚洲国产精品嫩草影院| 中国一级免费毛片| 色婷婷av久久久久久久| 中文字幕+乱码+中文乱码www| 欧美日韩日日摸| 国产精品欧美亚洲| 精品福利视频一区二区三区| 色中色在线视频| 在线观看欧美成人| av网站在线看| 韩剧1988在线观看免费完整版| 成人美女黄网站| 91视频-88av| 老牛影视av一区二区在线观看| 欧美 日韩 国产在线| 成人在线免费观看网站| 人妻无码一区二区三区四区| 99亚洲一区二区| 中文字幕第38页| 不卡一卡二卡三乱码免费网站| 最新中文字幕视频| 中文字幕一区二区5566日韩| 久久老司机精品视频| 色屁屁一区二区| www日本高清视频| 国产婷婷成人久久av免费高清| 午夜免费视频在线国产| 色综合久久精品亚洲国产| 刘亦菲一区二区三区免费看| 国产免费一区二区三区在线能观看| 51社区在线成人免费视频| 日本一区二区精品| 黄色亚洲精品| 欧美黄色性生活| jvid福利写真一区二区三区| 蜜桃av免费在线观看| 精品国产91久久久| 国产女人18毛片水真多| 日韩精品有码在线观看| 中文字幕免费高清电视剧网站在线观看| 97超级碰碰碰久久久| 亚洲高清影院| 欧美日韩精品免费看| 欧美日韩国内| 最新国产黄色网址| 久久蜜臀精品av| 国产精品theporn动漫| 欧美军同video69gay| 清纯唯美亚洲色图| 欧美激情第6页| 欧美在线se| 午夜欧美一区二区三区免费观看| 在线观看一区| 日本一二三区在线| 国产精品九色蝌蚪自拍| 男人天堂2024| 亚洲精品福利在线观看| 国产三级在线播放| 成人av色在线观看| 欧美日韩久久精品| 精品人妻一区二区三区四区在线 | 亚洲亚裔videos黑人hd| 国产v日韩v欧美v| 99re6在线| 91成人网在线观看| 国产九九热视频| 国产欧美日韩亚州综合 | 欧美第一黄网| av成人国产| 男男做爰猛烈叫床爽爽小说| 一区二区三区 在线观看视频| 一级黄色片在线观看| 色婷婷综合久久久久| yw.尤物在线精品视频| 日本视频一区二区不卡| 日韩精品乱码av一区二区| 久久精品国产亚洲av久| 日韩欧美在线网址| 日韩在线免费播放| 国产99久久久欧美黑人 | 日韩有吗在线观看| 今天免费高清在线观看国语| 国产主播一区二区| 精品国产乱码久久久久久鸭王1| 91精品国产综合久久香蕉麻豆 | 51久久精品夜色国产麻豆| 玖玖玖免费嫩草在线影院一区| 极品美女扒开粉嫩小泬| 99riav一区二区三区| 国产日产精品一区二区三区| 亚洲欧美在线磁力| 日韩中文影院| 亚洲一区二区三区在线观看视频| 日本aⅴ亚洲精品中文乱码| 亚洲一级黄色录像| 欧美日本国产一区| av片在线观看| 国产一区精品在线| 久久久久中文| 午夜国产福利视频| 日韩免费电影一区| av资源在线| 色999五月色| 国产真实乱子伦精品视频| 久久精品国产亚洲AV无码男同| 亚洲国产精品va| 91看片一区| 久久久国产精华液999999| 国产电影一区二区三区| 亚洲 欧美 日韩 综合| 国产一区二区三区丝袜 | 日本在线不卡视频| 成人一级黄色大片| 亚洲丁香婷深爱综合| 日本欧美韩国| 四虎精品欧美一区二区免费| av网站免费线看精品| 中文字幕 自拍偷拍| 欧美肥婆姓交大片| 伊甸园亚洲一区| www.午夜av| 同产精品九九九| 婷婷激情在线| 精品国产免费人成电影在线观...| 久久亚洲一区| 成人观看免费视频| 一道本无吗dⅴd在线播放一区| 警花av一区二区三区| 大肉大捧一进一出好爽动态图| 亚洲欧美色图小说| 欧美视频综合| 国产福利久久|