練習(xí) 51 - 從瀏覽器獲取輸入 - 笨辦法學(xué)Python3

練習(xí) 51. 從瀏覽器獲取輸入

雖然能讓瀏覽器顯示“Hello World”是件很激動人心的事情丧荐,但是如果能讓用戶通過表單(form)向你的應(yīng)用程序提交文本豫柬,那就更令人興奮了。在這個練習(xí)中琼蚯,我們會使用 form 改進(jìn)你的 web 程序僵蛛,并且將用戶相關(guān)的信息保存到他們的“會話(session)”中。

Web 是如何工作的瑟幕?

該學(xué)點無趣的東西了磕蒲。在創(chuàng)建 form 前你需要先多學(xué)一點關(guān)于 web 的工作原理。這里的描述并不完整只盹,但是相當(dāng)準(zhǔn)確辣往,在你的程序出錯時,它會幫你找到出錯的原因殖卑。另外站削,如果你理解了 form 的應(yīng)用,那么創(chuàng)建 form 對你來說就會更容易孵稽。

我會從一個簡單的圖示講起许起,它向你展示了 web 請求的不同部分十偶,以及信息傳遞的大致流程:為了方便講述一個常規(guī)請求(request)的流程,我在每條線上面加了字母標(biāo)簽以作區(qū)別:

request流程.png
  1. 你在瀏覽器輸入網(wǎng)址 http://test.com//园细,它會通過你電腦的網(wǎng)絡(luò)設(shè)備發(fā)送請求(線路 A)惦积。

  2. 你的請求被傳送到互聯(lián)網(wǎng)(線路 B),然后再抵達(dá)遠(yuǎn)程服務(wù)器(線路 C)猛频,然后我的服務(wù)器會接受這個請求狮崩。
    ai醬注: 這里之所以用“my server”是因為舊版書中,作者舉例用的鏈接是 http://learnpythonthehardway.org/鹿寻,這是作者自己的網(wǎng)站睦柴,所以對應(yīng)也會指向他的服務(wù)器。在新版書中毡熏,雖然更換了鏈接坦敌,但是作者并沒有對這里的表述加以更正。

  3. 我的服務(wù)器接受請求后招刹,我的 web 應(yīng)用程序就會去處理這個請求(線路 D),然后我的 Python 代碼會去運行 index.GET 這個“處理程序(handler)”窝趣。

  4. 在代碼 return 的時候疯暑,我的 Python 服務(wù)器就會發(fā)出響應(yīng)(response),這個響應(yīng)會再通過線路 D 傳遞到你的瀏覽器哑舒。

  5. 運行這個網(wǎng)站的服務(wù)器會從線路 D 獲得響應(yīng)妇拯,然后服務(wù)器將這個網(wǎng)站通過線路 C 傳回至互聯(lián)網(wǎng)。

  6. 響應(yīng)通過互聯(lián)網(wǎng)由線路 B 傳至你的計算機洗鸵,計算機的網(wǎng)卡再通過線路 A 將響應(yīng)傳給你的瀏覽器越锈。

  7. 最后,你的瀏覽器顯示了這個響應(yīng)的內(nèi)容膘滨。

這段描述中有幾個術(shù)語需要你了解一下甘凭,以便你在談?wù)?web 應(yīng)用時能夠明白并應(yīng)用它們:

瀏覽器(browser) 這是你幾乎每天都會用到的軟件。大部分人并不知道它真正的原理火邓,他們只會把它叫作“網(wǎng)”(the Internet)丹弱。它的作用其實是接收你輸入到地址欄網(wǎng)址(例如http://learnpythonthehardway.org),然后使用該信息向該網(wǎng)址對應(yīng)的服務(wù)器提出請求铲咨。

地址(address) 通常這是一個像 http://test.com// 一樣的 URL (Uniform Resource Locator躲胳,統(tǒng)一資源定位器),它告訴瀏覽器該打開哪個網(wǎng)站纤勒。前面的 http 指出了你要使用的協(xié)議 (protocol)坯苹,這里我們用的是“超文本傳輸協(xié)議(Hyper-Text Transport Protocol)”。你還可以試試 ftp://ibiblio.org/ 摇天,這是一個“FTP 文件傳輸協(xié)議(File Transport Protocol)”的例子粹湃。test.com 這部分是“主機名(hostname)”恐仑,也就是一個便于人閱讀和記憶的地址,主機名會被匹配到一串叫作“IP 地址”的數(shù)字上面再芋,這個“IP 地址”就相當(dāng)于網(wǎng)絡(luò)中一臺計算機的電話號碼菊霜,通過這個號碼可以訪問到這臺計算機。最后济赎,URL 后面還可以跟一個路徑鉴逞,就像 http://test.com//book/ 中的 /book/ 部分,它對應(yīng)的是服務(wù)器上的某個文件或者某些資源司训,通過訪問這樣的網(wǎng)址构捡,你可以向服務(wù)器發(fā)出請求,然后獲得這些資源壳猜。網(wǎng)站地址還有很多別的組成部分勾徽,不過這些是最主要的。

連接(connection) 一旦瀏覽器知道了你想用的協(xié)議(http)统扳、你想訪問的服務(wù)器(http://test.com/)喘帚、以及該服務(wù)器需要獲取的資源,它就要創(chuàng)建一個連接咒钟。瀏覽器會讓操作系統(tǒng)(Operating System, OS)打開計算機的一個“端口(port)”(通常是 80 端口)吹由,端口準(zhǔn)備好以后,操作系統(tǒng)會回傳給你的程序一個類似文件的東西朱嘴,它所做的事情就是通過網(wǎng)絡(luò)傳輸和接收數(shù)據(jù)倾鲫,讓你的計算機和 http://test.com/ 這個網(wǎng)站所屬的服務(wù)器之間實現(xiàn)數(shù)據(jù)交換。當(dāng)你使用 http://localhost:8080/ 訪問你自己的站點時萍嬉,發(fā)生的事情其實是一樣的乌昔,只不過這次你告訴了瀏覽器要訪問的是你自己的計算機(localhost),要使用的端口不是默認(rèn)的 80壤追,而是 8080磕道。你還可以直接訪問 http://test.com:80/,這和不輸入端口效果一樣行冰,因為 HTTP 的默認(rèn)端口本來就是 80捅厂。

請求(request) 你的瀏覽器通過你提供的地址建立了連接,現(xiàn)在它需要從遠(yuǎn)端服務(wù)器要到它(或你)想要的資源资柔。如果你在 URL 的結(jié)尾加了 /book/焙贷,那你想要的就是 /book/ 對應(yīng)的文件或資源,大部分的服務(wù)器會直接為你調(diào)用 /book/index.html 這個文件贿堰,不過我們就假裝它不存在好了辙芍。瀏覽器為了獲得服務(wù)器上的資源,它需要向服務(wù)器發(fā)送一個“請求”。這里我就不講細(xì)節(jié)了故硅,你只需要明白庶灿,為了得到服務(wù)器上的內(nèi)容,它必須先向服務(wù)器發(fā)送一個請求才行吃衅。有意思的是往踢,“資源”不一定非要是文件。例如當(dāng)瀏覽器向你的應(yīng)用程序提出請求的時候徘层,服務(wù)器返回的其實是你的 Python 代碼生成的一些東西峻呕。

服務(wù)器(server) 服務(wù)器指的是瀏覽器另一端連接的計算機,它知道如何回應(yīng)瀏覽器請求的文件和資源趣效。大部分的 web 服務(wù)器只要發(fā)送文件就可以了瘦癌,這也是服務(wù)器流量的主要部分。不過你學(xué)的是使用 Python 組建一個服務(wù)器跷敬,這個服務(wù)器知道如何接受請求讯私,然后返回用 Python 處理過的字符串。當(dāng)你使用這種處理方式時西傀,你其實是假裝把文件發(fā)給了瀏覽器斤寇,其實你用的都只是代碼而已。就像你在《練習(xí) 50》中看到的拥褂,要構(gòu)建一個“響應(yīng)”其實也不需要多少代碼娘锁。

響應(yīng)(response) 這就是你的服務(wù)器回復(fù)你的請求,發(fā)回至瀏覽器的 HTML(包括 css肿仑、javascript 或 images)致盟。以文件響應(yīng)為例碎税,服務(wù)器只要從磁盤讀取文件尤慰,發(fā)送給瀏覽器就可以了,不過它還要將這些內(nèi)容包在一個特別定義的“頭部信息(header)”中雷蹂,這樣瀏覽器就會知道它獲取的是什么類型的內(nèi)容伟端。以你的 web 應(yīng)用程序為例,你發(fā)送的其實還是一樣的東西匪煌,包括 header 也一樣责蝠,只不過這些數(shù)據(jù)是你用 Python 代碼即時生成的。

這可以算是你能在網(wǎng)上找到的關(guān)于瀏覽器如何訪問網(wǎng)站的最快的快速課程了萎庭。這個課程應(yīng)該可以幫你更容易地理解本節(jié)的練習(xí)霜医,如果你還是不明白,就找找資料多多了解這方面的信息驳规,直到你明白為止肴敛。有一個很好的方法,就是你對照著上面的圖示,把你在《練習(xí) 50》中創(chuàng)建的 web 程序中的內(nèi)容分成幾個部分医男,讓其中的各部分對應(yīng)到上面的圖示中砸狞。如果你可以正確地將程序的各部分對應(yīng)到這個圖示,那你就大致明白它的工作原理了镀梭。

表單(forms)是如何工作的

熟悉“表單”最好的方法就是寫一個可以接收表單數(shù)據(jù)的程序出來刀森,然后看你可以對它做些什么。先將你的 app.py 文件修改成下面的樣子:

form_test.py

1   from flask import Flask
2   from flask import render_template
3   from flask import request 
4
5   app = Flask(__name__) 
6
7   @app.route("/hello")
8   def index():
9       name = request.args.get('name', 'Nobody') 
10
11      if name:
12          greeting = f"Hello, {name}"
13      else:
14          greeting = "Hello World" 
15
16      return render_template("index.html", greeting=greeting) 
17
18  if __name__ == "__main__":
19      app.run()

重啟 flask(按 CTRL + C报账,然后再次運行)確保它再次加載研底,然后用瀏覽器訪問 http://localhost:5000/hello,應(yīng)該會顯示 “I just wanted to say Hello, Nobody.” 接著笙什,把瀏覽器中的 URL 改為 http://localhost:5000/hello?name=Frank飘哨,你會看到 “Hello, Frank.” 最后,把 name=Frank 這里改成你的名字琐凭,它就會對你說 Hello算芯。

讓我們拆解一下腳本中的這些變更:

  1. 我們沒有直接為 greeting 賦值,而是使用了 request.args 從瀏覽器獲取數(shù)據(jù)栽烂。這是一個用鍵值對(key=value pairs) 來包含表單值的簡單字典撑毛。
  2. 然后我用新的 name 構(gòu)建 greeting,這句你應(yīng)該已經(jīng)很熟悉了愁憔。
  3. 其他的內(nèi)容和以前是一樣的腕扶,我們就不再分析了。

URL 中還可以包含多個參數(shù)吨掌。將本例的兩個變量改成這樣:http://localhost:5000/hello?name=Frank&greet=Hola半抱。然后修改代碼,讓它像這樣獲取 namegreet

greet = request.args.get( ' greet ' , ' Hello ' ) 
greeting = f"{greet}, {name}"

你還應(yīng)該試著不在 URL 上給出 greet 和 name 參數(shù)膜宋,只讓瀏覽器訪問 http://localhost:5000/hello窿侈,然后你會看到,name 會默認(rèn)為 “Nobody”秋茫,greet 會默認(rèn)為 “Hello”史简。

創(chuàng)建 HTML 表單

在 URL 上傳遞參數(shù)也可以,但就是有點丑肛著,而且對普通用戶來說有點難用圆兵。你真正想要的是一個“發(fā)送表單”(POST form),這是一個特殊的 HTML 文件枢贿,里面有一個 <form> 標(biāo)簽殉农。這個表單會從用戶那里收集信息,然后發(fā)送給你的網(wǎng)站局荚,就像你之前做的那樣超凳。

讓我們來快速創(chuàng)建一個,從中你可以看出它的工作原理。你需要創(chuàng)建一個新的 HTML 文件 templates/hello_form.html:

hello_form.html

<html>
    <head>
        <title>Sample Web Form</title>
    </head>
<body>

<h1>Fill Out This Form</h1>

<form action="/hello" method="POST">
    A Greeting: <input type="text" name="greet">
    <br/>
    Your Name: <input type="text" name="name">
    <br/>
    <input type="submit">
</form>

</body>
</html>

然后你需要把 app.py 改成這樣:

app.py

1   from flask import Flask
2   from flask import render_template
3   from flask import request 
4
5   app = Flask(__name__) 
6
7   @app.route("/hello", methods=['POST', 'GET'])
8   def index():
9       greeting = "Hello World" 
10
11      if request.method == "POST":
12          name = request.form['name']
13          greet = request.form['greet']
14          greeting = f"{greet}, {name}"
15          return render_template("index.html", greeting=greeting)
16      else:
17          return render_template("hello_form.html") 
18
19
20  if __name__ == "__main__":
21      app.run()

改完之后聪建,再次重啟 web 應(yīng)用钙畔,像之前一樣刷新瀏覽器。

這次你會看到一個表單金麸,向你獲取“A Greeting”和“Your Name.”擎析。當(dāng)你點擊表單上的提交( Submit )按鈕時,它會給你跟之前一樣的問候挥下。不過這次揍魂,瀏覽器上面的 URL 還是 http://localhost:5000/hello,哪怕你已經(jīng)傳遞了參數(shù)棚瘟。

讓這個發(fā)揮作用的是 hello_form.html 文件中的這一行:<form action="/hello" method="POST">现斋。這告訴瀏覽器:

  1. 從表單中的各個欄位收集用戶輸入的數(shù)據(jù)。
  2. 使用一種 POST 類型的請求偎蘸,將這些數(shù)據(jù)發(fā)送給服務(wù)器庄蹋。這是另外一種瀏覽器請求,它會將表單欄位“隱藏”起來迷雪。
  3. 將這個請求發(fā)送至 /hello URL限书,這是由 action="/hello" 這部分內(nèi)容告訴瀏覽器的。

你可以看到這兩個 <input> 標(biāo)簽是如何和你新代碼中的變量名相匹配的章咧。還要注意一下倦西,在 class index 里面,我沒有用 GET 方法赁严,而是使用了 POST 方法扰柠。這個新程序的工作原理如下:

  1. 你的新請求像之前一樣去到了 index(),不過現(xiàn)在有一個 if 語句來檢查 request.method 是 "POST" 還是 "GET" 方法疼约。這樣瀏覽器就能告訴 app.py 一個請求是表單提交還是 URL 參數(shù)卤档。

  2. 如果 request.method 是 "POST",程序就會對表單填寫和提交的內(nèi)容進(jìn)行處理忆谓,并返回合適的問候語裆装。

  3. 如果 request.method 是其他東西踱承,那你只要返回 hello_form.html 讓用戶來填寫倡缠。

作為練習(xí),在 templates/index.html 中添加一個鏈接茎活,讓它指向 /hello昙沦,這樣你可以反復(fù)填寫、提交表單并查看結(jié)果载荔。

確認(rèn)你可以解釋清楚這個鏈接的工作原理盾饮,以及它是如何讓你實現(xiàn)在
templates/index.htmltemplates/hello_form.html 之間循環(huán)跳轉(zhuǎn)的,還有就是要明白你新修改過的 Python 代碼中,運行的是哪一部分代碼丘损。

創(chuàng)建布局模板(layout template)

在你下一節(jié)練習(xí)創(chuàng)建游戲的過程中普办,你需要創(chuàng)建很多的小 HTML 頁面。如果你每次都寫一個完整的網(wǎng)頁徘钥,你會很快感覺到厭煩的衔蹲。幸運的 是你可以創(chuàng)建一個“布局模板”,也就是一種提供了通用的頭文件(headers)和腳注(footers)的外殼模板呈础,你可以用它將你所有的其他網(wǎng)頁包裹起來舆驶。好程序員會盡可能減少重復(fù)動作,所以要做一個好程序員而钞,使用布局模板是很重要的沙廉。

templates/index.html 修改為這樣:

index_laid_out.html

{% extends "layout.html" %}

{% block content %}
{% if greeting %}
    I just wanted to say
    <em style="color: green; font-size: 2em;">{{ greeting }}</em>.
{% else %}
    <em>Hello</em>, world!
{% endif %}

{% endblock %}

然后將 templates/hello_form.html 修改為這樣:

hello_form_laid_out.html

{% extends "layout.html" %}
 
{% block content %}

<h1>Fill Out This Form</h1>

<form action="/hello" method="POST">
    A Greeting: <input type="text" name="greet">
    <br/>
    Your Name: <input type="text" name="name">
    <br/>
    <input type="submit">
</form>

{% endblock %}

我們所做的就是把每一個頁面頂部和底部反復(fù)用到的“boilerplate”(樣板)代碼去掉。這些被去掉的代碼會被放到一個單獨的 templates/layout.html 文件中臼节,之后撬陵,這些反復(fù)用到的代碼就由 layout.html 來提供了。

修改好之后网缝,創(chuàng)建一個 templates/layout.html 文件袱结,內(nèi)容如下:

layout.html

<html>
<head>
    <title>Gothons From Planet Percal #25</title>
</head>
<body>

{% block content %}

{% endblock %}
</body>
</html>

這個文件和普通的模板文件類似,不過它會收到其它模板傳遞的內(nèi)容途凫,并將它們“包裹”起來垢夹。任何寫在這里的內(nèi)容都無需寫在別的模板中了。你的其他 HTML 模板會被插入到 {% block content %} 中维费。Flask 知道要把 layout.html 文件用作布局果元,因為你在模板的頂部放了 {% extends "layout.html" %}

為表單撰寫自動測試代碼

使用瀏覽器測試 web 程序是很容易的犀盟,只要點刷新按鈕就可以了而晒。不過畢竟我們是程序員嘛,如果我們可以寫一些代碼來測試我們的程序阅畴,為什么還要重復(fù)手動測試呢倡怎?接下來你要做的,就是為你的 web 程序?qū)懸粋€小測試贱枣。這會用到你在《練習(xí) 47》學(xué)過的一些東西监署,如果你不記得的話,可以回去復(fù)習(xí)一下纽哥。

創(chuàng)建一個新文件钠乏,并命名為 tests/app_tests.py,其內(nèi)容如下:

app_tests.py

1   from nose.tools import *
2   from app import app 
3
4   app.config['TESTING'] = True
5   web = app.test_client() 
6
7   def test_index():
8       rv = web.get('/', follow_redirects=True)
9       assert_equal(rv.status_code, 404) 
10
11      rv = web.get('/hello', follow_redirects=True)
12      assert_equal(rv.status_code, 200)
13      assert_in(b"Fill Out This Form", rv.data) 
14
15      data = {'name': 'Zed', 'greet': 'Hola'}
16      rv = web.post('/hello', follow_redirects=True, data=data)
17      assert_in(b"Zed", rv.data)
18      assert_in(b"Hola", rv.data)

最后春塌,用 nosetests 運行這個測試程序晓避,來測試你的 web 應(yīng)用:

$ nosetests
.
---------------
Ran 1 test in 0.059s OK

我在這兒其實是把整個應(yīng)用都從 app.py 模塊中引入進(jìn)來了簇捍,然后手動運行它。flask 框架有一個非常簡單用來處理請求的 API俏拱,它看起來像這樣:

data = {'name': 'Zed', 'greet': 'Hola'}
rv = web.post('/hello', follow_redirects=True, data=data)

這意味著你可以用 post() 方法發(fā)送一個 POST 請求暑塑,然后把表單數(shù)據(jù)作為字典傳給它。其他都和測試 web.get() 請求一模一樣锅必。

tests/app_tests.py 自動測試腳本中梯投,我首先確認(rèn) / 返回了一個“404 Not Found”響應(yīng),因為這個 URL 其實是不存在的况毅。然后我檢查了 /hello 在 GET 和 POST 兩種請求的情況下都能正常工作分蓖。就算你沒有弄明白測試的原理,這些測試代碼應(yīng)該是很好讀懂的尔许。

花些時間研究一下這個最新版的 web 程序么鹤,重點研究一下自動測試的工作原理。確保你理解了將 app.py 做為一個模塊導(dǎo)入味廊,然后進(jìn)行自動化測試的流程蒸甜。這是一個很重要的技巧,它會引導(dǎo)你學(xué)到更多東西余佛。

附加練習(xí)

  1. 閱讀和 HTML 相關(guān)的更多資料柠新,然后為你的表單設(shè)計一個更好的輸出格式。你可以先在紙上設(shè)計出來辉巡,然后用 HTML 去實現(xiàn)它恨憎。
  2. 這是一道難題,試著研究一下如何進(jìn)行文件上傳郊楣,通過網(wǎng)頁上傳一張圖像憔恳,然后將其保存到磁盤中。
  3. 更難的難題净蚤,找到 HTTP RFC 文件(講述 HTTP 工作原理的技術(shù)文件)钥组,然后努力閱讀一下。這是一篇很無趣的文檔今瀑,不過偶爾你也會用到里邊的一些知識程梦。
  4. 又是一道難題,找人幫你設(shè)置一個 web 服務(wù)器橘荠,例如 Apache屿附、Nginx 或者 thttpd。試著讓服務(wù)器 serve 一下你創(chuàng)建的 .html.css 文件砾医。如果失敗了也沒關(guān)系拿撩,web 服務(wù)器本來就都有點爛衣厘。
  5. 完成上面的任務(wù)后休息一下如蚜,然后試著多創(chuàng)建一些 web 程序出來压恒。

拆解

這里很適合講一下如何拆解 web 應(yīng)用。你應(yīng)該這樣做:

  1. 打開 FLASK_DEBUG 會造成多大的損害错邦?注意做這個的時候別把自己電腦搞垮了探赫。

  2. 假設(shè)你沒有為表單設(shè)置默認(rèn)參數(shù),哪里會出錯撬呢?

  3. 你先檢查 POST 然后是“其他東西”伦吠。你可以用 curl 命令行工具生成不同的請求類型』昀梗看看會發(fā)生什么毛仪?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市芯勘,隨后出現(xiàn)的幾起案子箱靴,更是在濱河造成了極大的恐慌,老刑警劉巖荷愕,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衡怀,死亡現(xiàn)場離奇詭異,居然都是意外死亡安疗,警方通過查閱死者的電腦和手機抛杨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荐类,“玉大人怖现,你說我怎么就攤上這事∮窆蓿” “怎么了真竖?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長厌小。 經(jīng)常有香客問我恢共,道長,這世上最難降的妖魔是什么璧亚? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任讨韭,我火速辦了婚禮,結(jié)果婚禮上癣蟋,老公的妹妹穿的比我還像新娘透硝。我一直安慰自己,他們只是感情好疯搅,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布濒生。 她就那樣靜靜地躺著,像睡著了一般幔欧。 火紅的嫁衣襯著肌膚如雪罪治。 梳的紋絲不亂的頭發(fā)上丽声,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音觉义,去河邊找鬼雁社。 笑死,一個胖子當(dāng)著我的面吹牛晒骇,可吹牛的內(nèi)容都是我干的霉撵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼洪囤,長吁一口氣:“原來是場噩夢啊……” “哼徒坡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瘤缩,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤崭参,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后款咖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體何暮,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年铐殃,在試婚紗的時候發(fā)現(xiàn)自己被綠了海洼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡富腊,死狀恐怖坏逢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赘被,我是刑警寧澤是整,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站民假,受9級特大地震影響浮入,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜羊异,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一事秀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧野舶,春花似錦易迹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至一屋,卻和暖如春窘疮,著一層夾襖步出監(jiān)牢的瞬間袋哼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工考余, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留先嬉,地道東北人轧苫。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓楚堤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親含懊。 傳聞我的和親對象是個殘疾皇子身冬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

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