74-Swift之Alamofire的基本使用和介紹(GET/POST)

前言

本篇是介紹Alamofire 的基本使用,對于還不會引入Alamofire的小伙伴可以看《73-Swift之Pods(CocoaPods)的Alamofire的引入的詳細(xì)指導(dǎo)》

Alamofire 是啥?

Alamofire是自2014年Swift 推出之后,AFNetworking的作者 [Mattt Thompson] 便提交了一個(gè)新的類似于AFNetworking 的網(wǎng)絡(luò)基礎(chǔ)框架,并且是專門使用最新的Swift 語言來編寫的,其名為:Alamofire

Alamofire 的優(yōu)點(diǎn)

  • 鏈?zhǔn)降恼埱?響應(yīng)方法(GET&POST等)
  • URLEncoding / JSONEncoding / PropertyListEncoding 參數(shù)編碼
  • 上傳類型支持:文件(File )、數(shù)據(jù)(Data )、流(Stream)以及MultipartFormData
  • 支持文件下載,下載支持?jǐn)帱c(diǎn)續(xù)傳
  • 支持使用NSURLCredential進(jìn)行身份驗(yàn)證
  • HTTP響應(yīng)驗(yàn)證validate()

Alamofire 對請求結(jié)果的解析方法提供如下

  • response 以請求DefaultDataResponse的對象返回請求結(jié)果。

  • responseData 這是將請求的結(jié)果以二進(jìn)制流的形式解析。

  • responseJSON 這是將請求的結(jié)果以JSON的形式解析。

  • responseString 這是將請求的結(jié)果以字符串的形式解析。

  • responsePropertyList 這是將請求的結(jié)果以PLIST形式解析。

Alamofire 的GET請求方法和請求解析方法的介紹和使用

1、 無參數(shù)的Alamofire 的GET請求和解析方式的介紹

// MARK: Alamofire 的Get請求
func alamofireGet1() -> Void {
    /**
       該請求只有一個(gè)參數(shù) 'URLRequest',并返回請求對象(DataRequest)。我們可以處理請求對象(DataRequest)獲取我們需要的數(shù)據(jù)。
     */
    let dataRequest:DataRequest = Alamofire.request("http://www.lxweimin.com/u/23dd8d9701bf")
    
    // 輸出請求返回的對象
    print(dataRequest)
    /**
     輸出結(jié)果
     GET http://www.lxweimin.com/u/23dd8d9701bf
     */
    
    // 解析請求的對象
    dataRequest.response { (DDResponse) in
        // 獲取請求的狀態(tài)碼
        let stateCode = DDResponse.response?.statusCode
        print(stateCode!)
        
        // 獲取請求的數(shù)據(jù)
        print(DDResponse.data!)// 只輸出數(shù)據(jù)有多少字節(jié)數(shù)
        // 將數(shù)據(jù)轉(zhuǎn)化為字符串
        let dataStr = String.init(data: DDResponse.data!, encoding:String.Encoding.utf8)
        print(dataStr!)
        
        // TODO: 輸出請求對象
        let requestSwf = DDResponse.request
        print(requestSwf!)
        /*通過請求對象,我們可以獲取請求的一系列信息*/
        // 請求頭文件
        print(requestSwf?.allHTTPHeaderFields as Any)
        // 獲取請求的緩存規(guī)則
        print(requestSwf?.cachePolicy as Any)
        // 獲取請求體(body)
        print(requestSwf?.httpBody as Any)
        // 獲取請求的方法
        print(requestSwf?.httpMethod as Any)
        
        
        // TODO: 輸出請求響應(yīng)對象
        let responseSwf = DDResponse.response
        print(responseSwf!)
        /**
         輸出響應(yīng)對象:
         <NSHTTPURLResponse: 0x608000221020> { URL: http://www.lxweimin.com/u/23dd8d9701bf } { status code: 200, headers {
         "Cache-Control" = "max-age=0, private, must-revalidate";
         Connection = "keep-alive";
         "Content-Encoding" = gzip;
         "Content-Type" = "text/html; charset=utf-8";
         Date = "Sat, 30 Sep 2017 06:43:45 GMT";
         Etag = "W/\"663fd325a56556576a8facd92d50bedd\"";
         Server = Tengine;
         "Set-Cookie" = "_maleskine_session=Y1JTZ2xhYnZ6b3dMZnZaZmVQeHZqVFN5L2QyWDJmaURtcVVBNXFGSXhRWlMvTUxzUWRhTkRFdy83NVAzbW0yNHhqQ05KNkN1WFJTTURTSkNYVnkzYmV6Wm96bmZyVU1kY0VQK3l6bENwN1JUVmdEaGtVY2NBUEdjbzBCZjAvdGVDTWRvRkhlZG16c2tjOGUzSnRvTVVBQWNNYUZyazhNRXlWellNeFFnNHFISTZMQ213bzFKNzV5OEdkYjF5VGRKbE9HdUJtWGpqV0VKU1RNcVJ3TktnMEFjclhFdFRtS3dKYngzek9pM2dWbGcyMmtQc0dLRU1RbDk2bUN2WW9jd3N3OWNMeFFqRkMrK08vYU5aWklEakxIanc2T1k3WjNsbFB1OVF4Rmd1VFZ0b1p2SFZnQ3l0WVVmZFM1KzZ4YmEzNTFhcjhVNHE5K0dacDlsM3RtMDBRPT0tLWxWaTQwNGpwVmZVaHdjNnc3Rk9teUE9PQ%3D%3D--a78f5fd47ad6bf048e57fd6701649281b26b2c63; path=/; HttpOnly";
         "Transfer-Encoding" = Identity;
         "X-Content-Type-Options" = nosniff;
         "X-Frame-Options" = DENY;
         "X-Request-Id" = "33b02181-e572-423c-ac45-a373e55edd6b";
         "X-Runtime" = "0.078608";
         "X-Via" = "1.1 wdx18:10 (Cdn Cache Server V2.0)";
         "X-XSS-Protection" = "1; mode=block";
         } }
         */
        
        // TODO: 輸出請求的錯誤信息
        print(DDResponse.error as Any)
        
        // TODO: 獲取請求/響應(yīng)統(tǒng)計(jì)信息的任務(wù)指標(biāo)。
        print(DDResponse.metrics!)
    }
    
    // TODO: 以二進(jìn)制數(shù)據(jù)形式輸出請求結(jié)果(也可以說解析請求結(jié)果)
    dataRequest.responseData { (data) in
         print(data)
         /*輸出:SUCCESS: 24039 bytes */
    }
    
    //TODO: 以JSON形式的輸出請求數(shù)據(jù)(以JOSN形式解析結(jié)果)
    dataRequest.responseJSON { (dataResponse) in
        // 輸出一個(gè) 'DataResponse' 的對象
        print(dataResponse)
        
        // 通過‘DataResponse’ 我們可以獲取一些信息
        // 1.請求的連接
        print(dataResponse.request!)
        
        // 2. 請求響應(yīng)的對象
        print(dataResponse.response!)
        
        // 3. 請求返回的數(shù)據(jù)
        print(dataResponse.data!)
        
        // 4. 服務(wù)器返回的結(jié)果
        print(dataResponse.result)
        
        // 5.完成請求需要的時(shí)間
        print(dataResponse.timeline)
    }
    
    //TODO: 將返回?cái)?shù)據(jù)以字符串的形式解析
    dataRequest.responseString { (dataResponse) in
        // 輸出一個(gè) 'DataResponse' 的對象
        print(dataResponse)
        
        // 通過‘DataResponse’ 我們可以獲取一些信息
        // 1.請求的連接
        print(dataResponse.request!)
        
        // 2. 請求響應(yīng)的對象
        print(dataResponse.response!)
        
        // 3. 請求返回的數(shù)據(jù)
        print(dataResponse.data!)
        
        // 4. 服務(wù)器返回的結(jié)果
        print(dataResponse.result)
        
        // 5.完成請求需要的時(shí)間
        print(dataResponse.timeline)
    }
    
    //TODO: 將數(shù)據(jù)以PLIST文件形式輸出
    dataRequest.responsePropertyList { (dataResponse) in
        // 輸出一個(gè) 'DataResponse' 的對象
        print(dataResponse)
        
        // 通過‘DataResponse’ 我們可以獲取一些信息
        // 1.請求的連接
        print(dataResponse.request!)
        
        // 2. 請求響應(yīng)的對象
        print(dataResponse.response!)
        
        // 3. 請求返回的數(shù)據(jù)
        print(dataResponse.data!)
        
        // 4. 服務(wù)器返回的結(jié)果
        print(dataResponse.result)
        
        // 5.完成請求需要的時(shí)間
        print(dataResponse.timeline)
    }
    
    //TODO: 在線程中處理請求的數(shù)據(jù)
    let dispathQu = DispatchQueue.main
    dataRequest.response(queue: dispathQu) { (ddataResponse) in
        // 返回一個(gè)‘DefaultDataResponse’ 對象
        print(ddataResponse)
        
        // 1、獲取請求體
        print(ddataResponse.request!)
        
        // 2、獲取請求響應(yīng)體
        print(ddataResponse.response!)
        
        // 3、獲取請求數(shù)據(jù)
        print(ddataResponse.data!)
        
        // 4、獲取請求的錯誤信息
        print(ddataResponse.error!)
    }
    
    // 請求的進(jìn)度
    print(dataRequest.progress)
}

2、Alamofire的帶參數(shù)的GET請求

// TODO: Alamofire的GET請求帶參數(shù)
func alamofireGet2() -> Void {
    let dataResponse = Alamofire.request("http://gc.ditu.aliyun.com/geocoding",parameters:["a":"北京"])
    // 請求返回的結(jié)果
    print(dataResponse)
    
    // 對請求的結(jié)果處理
    dataResponse.responseData { (dataRequ) in
        if let data = dataRequ.data {
            let strData = String.init(data: data, encoding: String.Encoding.utf8)
            print(strData!)
            /**
             輸出的結(jié)果:
             {"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
             */
        }
    }
}

3、Alamofire的GET請求和返回?cái)?shù)據(jù)一起處理的寫法

// TODO: Alamofire的GET請求和返回?cái)?shù)據(jù)一起處理的寫法
func alamofireGet3() -> Void {
    Alamofire.request("http://gc.ditu.aliyun.com/geocoding",parameters:["a":"北京"]).responseString { (dataResquest) in
        if let data = dataResquest.data {
            let strData = String.init(data: data, encoding: String.Encoding.utf8)
            print(strData!)
            /**
             輸出的結(jié)果:
             {"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
             */
        }
    }
}

Alamofire 的POST請求

// MARK: Alamofire的POST請求
func alamofirePost() -> Void {
    Alamofire.request("http://gc.ditu.aliyun.com/geocoding",method:.post ,parameters:["a":"北京"]).responseJSON { (dataRequest) in
        if let data = dataRequest.data {
            let strData = String.init(data: data, encoding: String.Encoding.utf8)
            print(strData!)
            /**
             輸出的結(jié)果:
             {"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
             */
        }
    }
}

POST 和 GET 的友情快遞

對于POST 和 GET的區(qū)別是:GET產(chǎn)生一個(gè)TCP數(shù)據(jù)包;POST產(chǎn)生兩個(gè)TCP數(shù)據(jù)包。對于GET方式的請求,瀏覽器會把http header和data一并發(fā)送出去,服務(wù)器響應(yīng)200(返回?cái)?shù)據(jù)); 而對于POST,瀏覽器先發(fā)送header,服務(wù)器響應(yīng)100 continue,瀏覽器再發(fā)送data,服務(wù)器響應(yīng)200 (返回?cái)?shù)據(jù))。

Alamofire 可以自定義請求

1、只定義請求方式的請求

// MARk:自定義請求
func customRequestMethod() -> Void {
    // 創(chuàng)建請求體
    let urlRequest = try! URLRequest.init(url: "http://www.lxweimin.com/u/23dd8d9701bf", method: .get)
    Alamofire.request(urlRequest).responseString { (dataRequest) in
         print(dataRequest.data!)
    }
}
method 可選參數(shù)如下:
public enum HTTPMethod: String {
    case options = "OPTIONS"
    case get     = "GET"
    case head    = "HEAD"
    case post    = "POST"
    case put     = "PUT"
    case patch   = "PATCH"
    case delete  = "DELETE"
    case trace   = "TRACE"
    case connect = "CONNECT"
}

2、可是設(shè)置請求的緩存策略和請求超時(shí)的時(shí)間的請求

// MARK: 可是設(shè)置請求的緩存策略和請求超時(shí)的時(shí)間
func customRequestMethod1() -> Void {
    // 創(chuàng)建請求體
    let urlRequest =  URLRequest.init(url: URL.init(string: "http://www.lxweimin.com/u/23dd8d9701bf")!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30)
    Alamofire.request(urlRequest).responseData { (dataQuest) in
         print(dataQuest.data!)
    }
}

@ cachePolicy 是請求緩存策略參數(shù)
@ timeoutInterval 是請求超時(shí)時(shí)間參數(shù)

3、可設(shè)置請求方式和請求頭的請求

// MARK: 可設(shè)置請求方式和請求頭的請求
func customRequestMethod2() -> Void {
    // 創(chuàng)建請求體
    let urlRequest = try! URLRequest.init(url: "http://www.lxweimin.com/u/23dd8d9701bf", method: .get, headers:["charset":"utf-8","Content-Type":"application/x-www-form-urlencoded","appKey":"NetWork小賤"])
    Alamofire.request(urlRequest).responseData { (dataRequest) in
         print(dataRequest.data!)
    }
}

@ method 設(shè)置請求方式
@ headers 設(shè)置請求頭

Alamofire 的上傳參數(shù)編碼的請求

Alamofire 的請求參數(shù)編碼有以下幾種:

  • 1、 URLEncoding 是 “URL” 網(wǎng)址編碼規(guī)則

  • 2、 JSONEncoding 是 “JSON” 格式編碼規(guī)則

  • 3、 PropertyListEncoding 是 “PLIST” 文件編碼規(guī)則

使用舉例如下:

//MARK: 上傳參數(shù)使用指定的編碼格式上傳的請求
func parameterCodingRequest() -> Void {
     // 請求的參數(shù)
    let parameter = ["type":"hot","offset":"0","limit":"10"]
    /**
     參數(shù)的所有編碼形式如下,即 “ParameterEncoding” 的擴(kuò)展對象:
     1、 URLEncoding  是 “URL” 網(wǎng)址編碼規(guī)則
     2、 JSONEncoding 是 “JSON” 格式編碼規(guī)則
     3、 PropertyListEncoding 是 “PLIST” 文件編碼規(guī)則
     */
    Alamofire.request("http://m.maoyan.com/movie/list.json", method: .get, parameters: parameter,
                      encoding: URLEncoding.default).responseJSON { (dataRequest) in
                        if let data = dataRequest.data {
                            print(String.init(data: data, encoding: String.Encoding.utf8)!)
                        }
    }
}

Alamofire 的 validate() 函數(shù)的介紹

1、 validate() 函數(shù)是啥?

確認(rèn)響應(yīng)有默認(rèn)可接受的200~299范圍內(nèi)的狀態(tài)碼,還有內(nèi)容類型匹配在Accept HTTP頭字段中指定的任何值。如果驗(yàn)證失敗,隨后對響應(yīng)處理程序的調(diào)用將會有一個(gè)相關(guān)的錯誤。

2、請求信息的驗(yàn)證之 “validate”

// MARK: 請求信息的驗(yàn)證之 “validate”
func verifyInformationRequest() -> Void {
    Alamofire.request("http://m.maoyan.com/cinemas.json").validate().responseJSON { (dataRequest) in
        switch dataRequest.result.isSuccess {
        case true:
            let data  = dataRequest.data
            let dict = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
            print(dict)
        case false:
            print("獲取信息失敗!!")
        }
    }
}

3、驗(yàn)證請求狀態(tài)碼在 “200~299” 之間的請求,否則,不驗(yàn)證。

// MARK: 驗(yàn)證請求狀態(tài)碼在 “200~299” 之間的請求,否則,不驗(yàn)證。
func requestStateCodeVerification() -> Void {
    Alamofire.request("http://m.maoyan.com/cinemas.json").validate(statusCode: [200,299]).responseJSON { (dataRequest) in
        switch dataRequest.result.isSuccess {
        case true:
            if let data = dataRequest.data {
                let dict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
                print(dict)
            }
        case false:
            print("獲取信息失敗!!!")
        }
    }
}

4、驗(yàn)證指定請求媒體信息格式的請求

// MARK: 驗(yàn)證指定請求媒體信息格式的請求
func verifyRequestMediaFormatRequest() -> Void {
    /**
     友情大爆炸:
     1、contentType : 即是 “Internet Media Type” 稱之為 互聯(lián)網(wǎng)媒體類型,也叫 “MIME”。作用是在 "HTTP" 請求頭中使用“contentType”來指定不同格式的請求信息。
     
     2、contentType 常見的媒體格式類型如下:
     text/html  :HTML格式
     text/plain :純文本格式
     text/xml   :XML格式
     image/gif  :gif圖片格式
     image/jpeg :jpg圖片格式
     image/png  :png圖片格式
     以application開頭的媒體格式類型:
     application/xhtml+xml :XHTML格式
     application/xml       :XML數(shù)據(jù)格式
     application/atom+xml  :Atom XML聚合格式
     application/json      :JSON數(shù)據(jù)格式
     application/pdf       :pdf格式
     application/msword    :Word文檔格式
     application/octet-stream :二進(jìn)制流數(shù)據(jù)(如常見的文件下載)
     application/x-www-form-urlencoded :<form encType=””>中默認(rèn)的encType,form表單數(shù)據(jù)被編碼為key/value格式發(fā)送到服務(wù)器(表單默認(rèn)的提交數(shù)據(jù)的格式)
     */
    Alamofire.request("http://m.maoyan.com/cinemas.json").validate(contentType: ["text/html","text/plain","application/json"]).responseJSON { (dataRequest) in
        switch dataRequest.result.isSuccess {
        case true:
            if let data = dataRequest.data {
                let dict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
                print(dict)
            }
        case false:
            print("獲取信息失敗!!!")
        }
    }
}

5、我們可以根據(jù)某個(gè)條件,來設(shè)定返回的驗(yàn)證結(jié)果 “ValidationResult”

// MARK: 我們可以根據(jù)某個(gè)條件,來設(shè)定返回的驗(yàn)證結(jié)果 “ValidationResult”
func customizationValidationResult() -> Void {
    Alamofire.request("http://m.maoyan.com/cinemas.json").validate { (urlRequest, httpUrlResponse, data) -> Request.ValidationResult in
        // 在這里我們可以提前檢驗(yàn) 請求的 “URLRequest”、“HTTPURLResponse” 和 返回的數(shù)據(jù) “Data” 等來設(shè)置請求返回的 “ValidationResult”
        if !(urlRequest?.url?.absoluteString.contains("NetWork"))! {
            let error = NSError.init(domain: "m.maoyan.com", code: 320, userInfo: ["msg":"請求不包含指定的參數(shù)"]) as Error
            return Request.ValidationResult.failure(error)
        }
        return Request.ValidationResult.success
        }.responseJSON { (dataRequest) in
            switch dataRequest.result.isSuccess {
            case true:
                if let data = dataRequest.data {
                    let dict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
                    print(dict)
                }
            case false:
                let errorInfo = dataRequest.result.error! as NSError
                print(errorInfo.userInfo)
                /**
                 輸出信息:["msg": "請求不包含指定的參數(shù)"]
                 */
            }
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,510評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內(nèi)容