iOS14開發(fā)-網(wǎng)絡(luò)

基礎(chǔ)知識(shí)

App如何通過(guò)網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)?

客戶服務(wù)器模型
  1. App 通過(guò)一個(gè) URL 向特定的主機(jī)發(fā)送一個(gè)網(wǎng)絡(luò)請(qǐng)求加載需要的資源。URL 一般是使用 HTTP(HTTPS)協(xié)議题翻,該協(xié)議會(huì)通過(guò) IP(或域名)定位到資源所在的主機(jī)浙宜,然后等待主機(jī)處理和響應(yīng)。
  2. 主機(jī)通過(guò)本次網(wǎng)絡(luò)請(qǐng)求指定的端口號(hào)找到對(duì)應(yīng)的處理軟件汛聚,然后將網(wǎng)絡(luò)請(qǐng)求轉(zhuǎn)發(fā)給該軟件進(jìn)行處理(處理的軟件會(huì)運(yùn)行在特定的端口)。針對(duì) HTTP(HTTPS)請(qǐng)求短荐,處理的軟件會(huì)隨著開發(fā)語(yǔ)言的不同而不同倚舀,如 Java 的 Tomcat、PHP 的 Apache忍宋、.net 的 IIS痕貌、Node.js 的 JavaScript 運(yùn)行時(shí)等)
  3. 處理軟件針對(duì)本次請(qǐng)求進(jìn)行分析,分析的內(nèi)容包括請(qǐng)求的方法糠排、路徑以及攜帶的參數(shù)等舵稠。然后根據(jù)這些信息,進(jìn)行相應(yīng)的業(yè)務(wù)邏輯處理乳讥,最后通過(guò)主機(jī)將處理后的數(shù)據(jù)返回(返回的數(shù)據(jù)一般為 JSON 字符串)柱查。
  4. App 接收到主機(jī)返回的數(shù)據(jù),進(jìn)行解析處理云石,最后展示到界面上唉工。
  5. 發(fā)送請(qǐng)求獲取資源的一方稱為客戶端。接收請(qǐng)求提供服務(wù)的一方稱為服務(wù)端汹忠。

基本概念

URL

  • Uniform Resource Locator(統(tǒng)一資源定位符)淋硝,表示網(wǎng)絡(luò)資源的地址或位置。
  • 互聯(lián)網(wǎng)上的每個(gè)資源都有一個(gè)唯一的 URL宽菜,通過(guò)它能找到該資源谣膳。
  • URL 的基本格式協(xié)議://主機(jī)地址/路徑

HTTP/HTTPS

  • HTTP—HyperTextTransferProtocol:超文本傳輸協(xié)議铅乡。
  • HTTPS—Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext Transfer Protocol Secure:超文本傳輸安全協(xié)議继谚。

請(qǐng)求方法

  • 在 HTTP/1.1 協(xié)議中,定義了 8 種發(fā)送 HTTP 請(qǐng)求的方法阵幸,分別是GET花履、POST、HEAD挚赊、PUT诡壁、DELETE、OPTIONS荠割、TRACE妹卿、CONNECT
  • 最常用的是 GETPOST

響應(yīng)狀態(tài)碼

狀態(tài)碼 描述 含義
200 Ok 請(qǐng)求成功
400 Bad Request 客戶端請(qǐng)求的語(yǔ)法出現(xiàn)錯(cuò)誤夺克,服務(wù)端無(wú)法解析
404 Not Found 服務(wù)端無(wú)法根據(jù)客戶端的請(qǐng)求找到對(duì)應(yīng)的資源
500 Internal Server Error 服務(wù)端內(nèi)部出現(xiàn)問(wèn)題箕宙,無(wú)法完成響應(yīng)

請(qǐng)求響應(yīng)過(guò)程

請(qǐng)求響應(yīng)過(guò)程

JSON

  • JavaScript Object Notation。
  • 一種輕量級(jí)的數(shù)據(jù)格式铺纽,一般用于數(shù)據(jù)交互扒吁。
  • 服務(wù)端返回給 App 客戶端的數(shù)據(jù),一般都是 JSON 格式室囊。

語(yǔ)法

  • 數(shù)據(jù)以鍵值對(duì)key : value形式存在。
  • 多個(gè)數(shù)據(jù)由,分隔魁索。
  • 花括號(hào){}保存對(duì)象融撞。
  • 方括號(hào)[]保存數(shù)組。

key與value

  • 標(biāo)準(zhǔn) JSON 數(shù)據(jù)的 key 必須用雙引號(hào)""粗蔚。
  • JSON 數(shù)據(jù)的 value 類型:
    • 數(shù)字(整數(shù)或浮點(diǎn)數(shù))
    • 字符串("表示)
    • 布爾值(true 或 false)
    • 數(shù)組([]表示)
    • 對(duì)象({}表示)
    • null

解析

  • 厘清當(dāng)前 JSON 數(shù)據(jù)的層級(jí)關(guān)系(借助于格式化工具)尝偎。
  • 明確每個(gè) key 對(duì)應(yīng)的 value 值的類型。
  • 解析技術(shù)
    • Codable 協(xié)議(推薦)鹏控。
    • JSONSerialization致扯。
    • 第三方框架。

URLSession

使用步驟

  1. 創(chuàng)建請(qǐng)求資源的 URL当辐。
  2. 創(chuàng)建 URLRequest抖僵,設(shè)置請(qǐng)求參數(shù)。
  3. 創(chuàng)建 URLSessionConfiguration 用于設(shè)置 URLSession 的工作模式和網(wǎng)絡(luò)設(shè)置缘揪。
  4. 創(chuàng)建 URLSession耍群。
  5. 通過(guò) URLSession 構(gòu)建 URLSessionTask,共有 3 種任務(wù)找筝。
    (1)URLSessionDataTask:請(qǐng)求數(shù)據(jù)的 Task蹈垢。
    (2)URLSessionUploadTask:上傳數(shù)據(jù)的 Task。
    (3)URLSessionDownloadTask:下載數(shù)據(jù)的 Task袖裕。
  6. 啟動(dòng)任務(wù)曹抬。
  7. 處理服務(wù)端響應(yīng),有 2 種方式急鳄。
    (1)通過(guò) completionHandler(閉包)處理服務(wù)端響應(yīng)谤民。
    (2)通過(guò) URLSessionDataDelegate(代理)處理請(qǐng)求與響應(yīng)過(guò)程的事件和接收服務(wù)端返回的數(shù)據(jù)。

基本使用

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // get()
        // post()
    }

    func get() {
        // 1. 確定URL
        let url = URL(string: "http://v.juhe.cn/toutiao/index?type=top&key=申請(qǐng)的key")
        // 2. 創(chuàng)建請(qǐng)求
        let urlRequest = URLRequest(url: url!)
        // cachePolicy: 緩存策略攒岛,App最常用的緩存策略是returnCacheDataElseLoad赖临,表示先查看緩存數(shù)據(jù),沒有緩存再請(qǐng)求
        // timeoutInterval:超時(shí)時(shí)間
        // let urlRequest = URLRequest(url: url!, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 5)
        let config = URLSessionConfiguration.default
        // 3. 創(chuàng)建URLSession
        let session = URLSession(configuration: config)
        // 4. 創(chuàng)建任務(wù)
        let task = session.dataTask(with: urlRequest) { data, _, error in
            if error != nil {
                print(error!)
            } else {
                if let data = data {
                    print(String(data: data, encoding: .utf8)!)
                }
            }
        }
        // 5. 啟動(dòng)任務(wù)
        task.resume()
    }

    func post() {
        let url = URL(string: "http://v.juhe.cn/toutiao/index")
        var urlRequest = URLRequest(url: url!)
        // 指明請(qǐng)求方法
        urlRequest.httpMethod = "POST"
        // 指明參數(shù)
        let params = "type=top&申請(qǐng)的key"
        // 設(shè)置請(qǐng)求體
        urlRequest.httpBody = params.data(using: .utf8)
        let config = URLSessionConfiguration.default
        // delegateQueue決定了代理方法在哪個(gè)線程中執(zhí)行
        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
        let task = session.dataTask(with: urlRequest)
        task.resume()
    }
}


// MARK:- URLSessionDataDelegate
extension ViewController: URLSessionDataDelegate {
    // 開始接收數(shù)據(jù)
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
        // 允許接收服務(wù)器的數(shù)據(jù)灾锯,默認(rèn)情況下請(qǐng)求之后不接收服務(wù)器的數(shù)據(jù)即不會(huì)調(diào)用后面獲取數(shù)據(jù)的代理方法
        completionHandler(URLSession.ResponseDisposition.allow)
    }

    // 獲取數(shù)據(jù)
    // 根據(jù)請(qǐng)求的數(shù)據(jù)量該方法可能會(huì)調(diào)用多次兢榨,這樣data返回的就是總數(shù)據(jù)的一段,此時(shí)需要用一個(gè)全局的Data進(jìn)行追加存儲(chǔ)
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        let result = String(data: data, encoding: .utf8)
        if let result = result {
            print(result)
        }
    }

    // 獲取結(jié)束
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let error = error {
            print(error)
        } else {
            print("=======成功=======")
        }
    }
}

注意:如果網(wǎng)絡(luò)請(qǐng)求是 HTTP 而非 HTTPS,默認(rèn)情況下吵聪,iOS 會(huì)阻斷該請(qǐng)求凌那,此時(shí)需要在 Info.plist 中進(jìn)行如下配置。

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

下載數(shù)據(jù)

class ViewController: UIViewController {
    // 下載進(jìn)度
    @IBOutlet var downloadProgress: UIProgressView!
    // 下載圖片
    @IBOutlet var downloadImageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        download()
    }

    func download() {
        let url = URL(string: "http://172.20.53.240:8080/AppTestAPI/wall.png")!
        let request = URLRequest(url: url)
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue())
        let task = session.downloadTask(with: request)
        task.resume()
    }
}

extension ViewController: URLSessionDownloadDelegate {
    // 下載完成
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // 存入沙盒
        let savePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
        // 文件類型根據(jù)下載的內(nèi)容決定
        let fileName = "\(Int(Date().timeIntervalSince1970)).png"
        let filePath = savePath + "/" + fileName
        print(filePath)
        do {
            try FileManager.default.moveItem(at: location, to: URL(fileURLWithPath: filePath))
            // 顯示到界面
            DispatchQueue.main.async {
                self.downloadImageView.image = UIImage(contentsOfFile: filePath)
            }
        } catch {
            print(error)
        }
    }

    // 計(jì)算進(jìn)度
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        DispatchQueue.main.async {
            self.downloadProgress.setProgress(Float(totalBytesWritten) / Float(totalBytesExpectedToWrite), animated: true)
        }
    }
}

上傳數(shù)據(jù)

上傳數(shù)據(jù)需要服務(wù)端配合吟逝,不同的服務(wù)端代碼可能會(huì)不一樣帽蝶,下面的上傳代碼適用于本人所寫的服務(wù)端代碼

  • 數(shù)據(jù)格式块攒。
上傳數(shù)據(jù)格式
  • 實(shí)現(xiàn)励稳。
class ViewController: UIViewController {
    let YFBoundary = "AnHuiWuHuYungFan"
    @IBOutlet var uploadInfo: UILabel!
    @IBOutlet var uploadProgress: UIProgressView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        upload()
    }

    func upload() {
        // 1. 確定URL
        let url = URL(string: "http://172.20.53.240:8080/AppTestAPI/UploadServlet")!
        // 2. 確定請(qǐng)求
        var request = URLRequest(url: url)
        // 3. 設(shè)置請(qǐng)求頭
        let head = "multipart/form-data;boundary=\(YFBoundary)"
        request.setValue(head, forHTTPHeaderField: "Content-Type")
        // 4. 設(shè)置請(qǐng)求方式
        request.httpMethod = "POST"
        // 5. 創(chuàng)建NSURLSession
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue())
        // 6. 獲取上傳的數(shù)據(jù)(按照固定格式拼接)
        var data = Data()
        let header = headerString(mimeType: "image/png", uploadFile: "wall.png")
        data.append(header.data(using: .utf8)!)
        data.append(uploadData())
        let tailer = tailerString()
        data.append(tailer.data(using: .utf8)!)
        // 7. 創(chuàng)建上傳任務(wù) 上傳的數(shù)據(jù)來(lái)自getData方法
        let task = session.uploadTask(with: request, from: data) { _, _, error in
            // 上傳完畢后
            if error != nil {
                print(error!)
            } else {
                DispatchQueue.main.async {
                    self.uploadInfo.text = "上傳成功"
                }
            }
        }
        // 8. 執(zhí)行上傳任務(wù)
        task.resume()
    }

    // 開始標(biāo)記
    func headerString(mimeType: String, uploadFile: String) -> String {
        var data = String()
        // --Boundary\r\n
        data.append("--" + YFBoundary + "\r\n")
        // 文件參數(shù)名 Content-Disposition: form-data; name="myfile"; filename="wall.jpg"\r\n
        data.append("Content-Disposition:form-data; name=\"myfile\";filename=\"\(uploadFile)\"\r\n")
        // Content-Type 上傳文件的類型 MIME\r\n\r\n
        data.append("Content-Type:\(mimeType)\r\n\r\n")

        return data
    }

    // 結(jié)束標(biāo)記
    func tailerString() -> String {
        // \r\n--Boundary--\r\n
        return "\r\n--" + YFBoundary + "--\r\n"
    }

    func uploadData() -> Data {
        let image = UIImage(named: "wall.png")
        let imageData = image!.pngData()
        return imageData!
    }
}

extension ViewController: URLSessionTaskDelegate {
    // 上傳進(jìn)去
    func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
        DispatchQueue.main.async {
            self.uploadProgress.setProgress(Float(totalBytesSent) / Float(totalBytesExpectedToSend), animated: true)
        }
    }
    
    // 上傳出錯(cuò)
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let error = error {
            print(error)
        }
    }
}

WKWebView

  • 用于加載 Web 內(nèi)容的控件。
  • 使用時(shí)必須導(dǎo)入WebKit模塊囱井。

基本使用

  • 加載網(wǎng)頁(yè)驹尼。
// 創(chuàng)建URL
let url = URL(string: "https://www.abc.edu.cn")
// 創(chuàng)建URLRequest
let request = URLRequest(url: url!)
// 創(chuàng)建WKWebView
let webView = WKWebView(frame: UIScreen.main.bounds)
// 加載網(wǎng)頁(yè)
webView.load(request)
  • 加載本地資源。
// 文件夾路徑
let basePath = Bundle.main.path(forResource: "localWeb", ofType: nil)!
// 文件夾URL
let baseUrl = URL(fileURLWithPath: basePath, isDirectory: true)
// html路徑
let filePath = basePath + "/index.html"
// 轉(zhuǎn)成文件
let fileContent = try? NSString(contentsOfFile: filePath, encoding: String.Encoding.utf8.rawValue)
// 創(chuàng)建WKWebView
let webView = WKWebView(frame: UIScreen.main.bounds)
// 加載html
webView.loadHTMLString(fileContent! as String, baseURL: baseUrl)

注意:如果是本地資源是文件夾庞呕,拖進(jìn)項(xiàng)目時(shí)新翎,需要勾選Create folder references,然后用Bundle.main.path(forResource: "文件夾名", ofType: nil)獲取資源路徑住练。

與JavaScript交互

創(chuàng)建WKWebView

lazy var webView: WKWebView = {
    // 創(chuàng)建WKPreferences
    let preferences = WKPreferences()
    // 開啟JavaScript
    preferences.javaScriptEnabled = true
    // 創(chuàng)建WKWebViewConfiguration
    let configuration = WKWebViewConfiguration()
    // 設(shè)置WKWebViewConfiguration的WKPreferences
    configuration.preferences = preferences
    // 創(chuàng)建WKUserContentController
    let userContentController = WKUserContentController()
    // 配置WKWebViewConfiguration的WKUserContentController
    configuration.userContentController = userContentController
    // 給WKWebView與Swift交互起一個(gè)名字:callbackHandler地啰,WKWebView給Swift發(fā)消息的時(shí)候會(huì)用到
    // 此句要求實(shí)現(xiàn)WKScriptMessageHandler
    configuration.userContentController.add(self, name: "callbackHandler")    
    // 創(chuàng)建WKWebView
    var webView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration)
    // 讓W(xué)KWebView翻動(dòng)有回彈效果
    webView.scrollView.bounces = true
    // 只允許WKWebView上下滾動(dòng)
    webView.scrollView.alwaysBounceVertical = true
    // 設(shè)置代理WKNavigationDelegate
    webView.navigationDelegate = self
    // 返回
    return webView
}()

創(chuàng)建HTML

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no"/>
    </head>
    <body>
        iOS傳過(guò)來(lái)的值:<span id="name"></span>
        <button onclick="responseSwift()">響應(yīng)iOS</button>
        <script type="text/javascript">
            // 給Swift調(diào)用
            function sayHello(name) {
                document.getElementById("name").innerHTML = name
                return "Swift你也好!"
            }
            // 調(diào)用Swift方法
            function responseSwift() {
                // 這里的callbackHandler是創(chuàng)建WKWebViewConfiguration是定義的
                window.webkit.messageHandlers.callbackHandler.postMessage("JavaScript發(fā)送消息給Swift")
            }
        </script>
    </body>
</html>

兩個(gè)協(xié)議

  • WKNavigationDelegate:判斷頁(yè)面加載完成讲逛,只有在頁(yè)面加載完成后才能在實(shí)現(xiàn) Swift 調(diào)用 JavaScript亏吝。WKWebView 調(diào)用 JavaScript:
// 加載完畢以后執(zhí)行
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    // 調(diào)用JavaScript方法
    webView.evaluateJavaScript("sayHello('WebView你好!')") { (result, err) in
        // result是JavaScript返回的值
        print(result, err)
    }
}
  • WKScriptMessageHandler:JavaScript 調(diào)用 Swift 時(shí)需要用到協(xié)議中的一個(gè)方法來(lái)盏混。JavaScript 調(diào)用 WKWebView:
// Swift方法顺呕,可以在JavaScript中調(diào)用
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    print(message.body)
}

ViewController

class ViewController: UIViewController {
    // 懶加載WKWebView
    ...

    // 加載本地html
    let html = try! String(contentsOfFile: Bundle.main.path(forResource: "index", ofType: "html")!, encoding: String.Encoding.utf8)

    override func viewDidLoad() {
        super.viewDidLoad()
        // 標(biāo)題
        title = "WebView與JavaScript交互"
        // 加載html
        webView.loadHTMLString(html, baseURL: nil)
        view.addSubview(webView)
    }
}

// 遵守兩個(gè)協(xié)議
extension ViewController: WKNavigationDelegate, WKScriptMessageHandler {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        ...
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        ...
    }
}

SFSafariViewController

  • iOS 9 推出的一種 UIViewController,用于加載與顯示 Web 內(nèi)容括饶,打開效果類似 Safari 瀏覽器的效果株茶。
  • 使用時(shí)必須導(dǎo)入SafariServices模塊。
import SafariServices

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        showSafariViewController()
    }

    func showSafariViewController() {
        // URL
        let url = URL(string: "https://www.baidu.com")
        // 創(chuàng)建SFSafariViewController
        let sf = SFSafariViewController(url: url!)
        // 設(shè)置代理
        sf.delegate = self
        // 顯示
        present(sf, animated: true, completion: nil)
    }
}

extension ViewController: SFSafariViewControllerDelegate {
    // 點(diǎn)擊左上角的完成(done)
    func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
        print(#function)
    }

    // 加載完成
    func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
        print(#function)
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末图焰,一起剝皮案震驚了整個(gè)濱河市启盛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌技羔,老刑警劉巖僵闯,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異藤滥,居然都是意外死亡鳖粟,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拙绊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)向图,“玉大人泳秀,你說(shuō)我怎么就攤上這事¢剩” “怎么了嗜傅?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)檩赢。 經(jīng)常有香客問(wèn)我吕嘀,道長(zhǎng),這世上最難降的妖魔是什么贞瞒? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任偶房,我火速辦了婚禮,結(jié)果婚禮上军浆,老公的妹妹穿的比我還像新娘蝴悉。我一直安慰自己,他們只是感情好瘾敢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尿这,像睡著了一般簇抵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上射众,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天碟摆,我揣著相機(jī)與錄音,去河邊找鬼叨橱。 笑死典蜕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罗洗。 我是一名探鬼主播愉舔,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伙菜!你這毒婦竟也來(lái)了轩缤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贩绕,失蹤者是張志新(化名)和其女友劉穎火的,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淑倾,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馏鹤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娇哆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湃累。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勃救,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出脱茉,到底是詐尸還是另有隱情剪芥,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布琴许,位于F島的核電站税肪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏榜田。R本人自食惡果不足惜益兄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望箭券。 院中可真熱鬧净捅,春花似錦、人聲如沸辩块。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)废亭。三九已至国章,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豆村,已是汗流浹背液兽。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掌动,地道東北人四啰。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像粗恢,于是被迫代替她去往敵國(guó)和親柑晒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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