Response.End() 與Response.Close()的區(qū)別

原來的測試程序,在Response.Flush()之后桐智,調(diào)用Response.End()稿壁,而出錯(cuò)的程序在Response.Flush()之后,調(diào)用Response.Close()记靡。直接將Close調(diào)用改為End后,問題消失团驱∶停看來問題的根源就在這里了。

MSDN對兩個(gè)方法給出的注釋是:

Close斷開客戶端的連接嚎花。

End結(jié)束當(dāng)前頁面的執(zhí)行寸痢。

看來確有不同。通過查看源碼紊选,Close 是服務(wù)器主動(dòng)斷開連接啼止,然后設(shè)置客戶端斷開連接的標(biāo)志,沒有其他的操作兵罢。而 End 會(huì)再次 Flush 當(dāng)前的內(nèi)容献烦,然后設(shè)置頁面結(jié)束的標(biāo)志,然后引發(fā) EndRequest 事件卖词,并不立即斷開客戶端連接巩那。

正是由于采取了不同的方法,導(dǎo)致最終的結(jié)果不同。Close 采用強(qiáng)硬手段即横,直接斷開客戶端連接噪生,也就使得 xmlhttp 組件不知道內(nèi)容是否已經(jīng)傳完,于是導(dǎo)致取不到內(nèi)容东囚。而 End 采用常規(guī)方法杠园,一步步操作,在 EndRequest 中明確告知后續(xù)操作自己正常結(jié)束舔庶,之后由后續(xù)操作正常斷開客戶端。說到這里陈醒,就不能不說惕橙,這跟.Net中http請求的生命周期相關(guān)。在http請求的生命周期中钉跷,Close 和 End 就像馬拉松的折返點(diǎn)一樣弥鹦,Close 相當(dāng)于到了折返點(diǎn)就直接坐汽車回起點(diǎn)了,而 End 相當(dāng)于到了折返點(diǎn)繼續(xù)跑回去爷辙。那么最終的結(jié)果肯定是不同的彬坏。

到目前為止,還是沒有解釋為什么啟用IIS壓縮功能之前是正常的膝晾,啟用壓縮功能之后就出錯(cuò)了呢栓始?其實(shí)我們已經(jīng)很接近真相了。因?yàn)閱⒂脡嚎s之后血当,服務(wù)器必須明確告訴客戶端幻赚,我傳給你的內(nèi)容是經(jīng)過壓縮的,壓縮方法是GZIP臊旭。這樣客戶端才能正確解析內(nèi)容落恼。而這個(gè)信息是放在http響應(yīng)頭的 Content-Encoding 中的。由于 Close 主動(dòng)斷開了連接离熏,使得IIS沒有機(jī)會(huì)加上這個(gè)響應(yīng)頭信息佳谦。所以就造成了采用Close方式時(shí),xmlhttp 組件獲取不到這個(gè)信息滋戳。由于沒啟用壓縮之前钻蔑,內(nèi)容已經(jīng)被接收完畢,并且xmlhttp可以正常解析胧瓜,所以在啟用壓縮之前矢棚,即使缺少 Content-Encoding 信息,功能也是正常的府喳。啟用壓縮之后蒲肋,xmlhttp 理解不了接收到的數(shù)據(jù),所以就出錯(cuò)了。


?不要使用Response.Close()

?? 1? 因?yàn)?Close()方法會(huì)調(diào)用HttpWorkerRequest.CloseConnection()方法兜粘。終止(Terminate)與客戶端的套接字連接申窘,并使得服務(wù)器,客戶端以及之間設(shè)施上的緩存(buffer)失效孔轴。導(dǎo)致發(fā)送到客戶端的數(shù)據(jù)丟失剃法。

???2?方法Response.End()是為了兼容經(jīng)典ASP程序,在Asp.NET 1.0中引入的路鹰,在調(diào)用后會(huì)拋出ThreadAbortException異常贷洲。成功時(shí)則中止(abort)當(dāng)前的線程,處理管道觸發(fā)EndRequest事件晋柱,不再處理之后的代碼优构。會(huì)以同步的方式將響應(yīng)內(nèi)容發(fā)送(flush)給客戶端。

????? 由于.NET 設(shè)計(jì)原因雁竞,Response.End()在WebForm框架下可以終止代碼執(zhí)行钦椭,不再處理End()之后的代碼。在MVC框架下則只是返回響應(yīng)流碑诉,不會(huì)中止代碼執(zhí)行彪腔。

?3?此外還可以使用HttpApplication.CompleteRequest()方法結(jié)束請求。

????? Response.Flush();

??????this.Context.ApplicationInstance.CompleteRequest();

?? 綜上所述:只有代碼發(fā)生錯(cuò)誤(惡意的攻擊)进栽,希望終止對于客戶端的響應(yīng)/連接時(shí)才可以使用Response.Close()

?? 如果你想結(jié)束請求德挣,并向客戶端發(fā)送請求則應(yīng)該優(yōu)先使用HttpApplication.CompleteRequest()方法。

參考文章:

1?http://weblogs.asp.net/hajan/why-not-to-use-httpresponse-close-and-httpresponse-end

2?http://stackoverflow.com/questions/1886729/httpresponse-end-vs-httpresponse-close-vs-httpresponse-suppresscontent

3?http://www.cnblogs.com/v5wa/p/3165367.html


requests是一個(gè)很實(shí)用的Python?HTTP客戶端庫泪幌,編寫爬蟲和測試服務(wù)器響應(yīng)數(shù)據(jù)時(shí)經(jīng)常會(huì)用到盲厌。可以說祸泪,Requests 完全滿足如今網(wǎng)絡(luò)的需求

本文全部來源于官方文檔 http://docs.python-requests.org/en/master/

安裝方式一般采用$ pip install requests吗浩。其它安裝方式參考官方文檔.

import?requests

GET請求

r? = requests.get('http://httpbin.org/get')

傳參

>>>?payload?=?{'key1':?'value1',?'key2':?'value2', 'key3':?None}

>>>?r?=?requests.get('http://httpbin.org/get',?params=payload)

http://httpbin.org/get?key2=value2&key1=value1

參數(shù)也可以傳遞列表

>>>?payload?=?{'key1':?'value1',?'key2': ['value2',?'value3']}

>>>?r?=?requests.get('http://httpbin.org/get',?params=payload)

>>>?print(r.url)

http://httpbin.org/get?key1=value1&key2=value2&key2=value3

r.text?返回headers中的編碼解析的結(jié)果,可以通過r.encoding = 'gbk'來變更解碼方式

r.content返回二進(jìn)制結(jié)果

r.json()返回JSON格式没隘,可能拋出異常

r.status_code

r.raw返回原始socket respons懂扼,需要加參數(shù)stream=True

>>>?r?=?requests.get('https://api.github.com/events',?stream=True)

>>>?r.raw

<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>

>>>?r.raw.read(10)

'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'

將結(jié)果保存到文件,利用r.iter_content()

with?open(filename,?'wb')?as?fd:

? ??????for?chunk?in?r.iter_content(chunk_size):

????????????????fd.write(chunk)


傳遞headers

>>>?headers?=?{'user-agent':?'my-app/0.0.1'}

>>>?r?=?requests.get(url,?headers=headers)

傳遞cookies

>>>?url?=?'http://httpbin.org/cookies'

>>>?r?=?requests.get(url,?cookies=dict(cookies_are='working'))

>>>?r.text

'{"cookies": {"cookies_are": "working"}}'

POST請求


傳遞表單

r?=?requests.post('http://httpbin.org/post',?data?=?{'key':'value'})

通常右蒲,你想要發(fā)送一些編碼為表單形式的數(shù)據(jù)—非常像一個(gè)HTML表單阀湿。 要實(shí)現(xiàn)這個(gè),只需簡單地傳遞一個(gè)字典給?data?參數(shù)瑰妄。你的數(shù)據(jù)字典 在發(fā)出請求時(shí)會(huì)自動(dòng)編碼為表單形式:

>>>?payload?=?{'key1':?'value1',?'key2':?'value2'}

>>>?r?=?requests.post("http://httpbin.org/post",?data=payload)

>>>?print(r.text)

{? ...? "form": {??? "key2": "value2",??? "key1": "value1"? },? ...}

很多時(shí)候你想要發(fā)送的數(shù)據(jù)并非編碼為表單形式的陷嘴。如果你傳遞一個(gè)?string?而不是一個(gè)dict?,那么數(shù)據(jù)會(huì)被直接發(fā)布出去间坐。

>>>?url?=?'https://api.github.com/some/endpoint'

>>>?payload?=?{'some':?'data'}

>>>?r?=?requests.post(url,?data=json.dumps(payload))

或者

>>>?r?=?requests.post(url,?json=payload)

傳遞文件

url?=?'http://httpbin.org/post'

>>>?files?=?{'file':?open('report.xls',?'rb')}

>>>?r?=?requests.post(url,?files=files)

配置files灾挨,filename, content_type and headers

files?=?{'file': ('report.xls',?open('report.xls',?'rb'),?'application/vnd.ms-excel', {'Expires':?'0'})}

files?=?{'file': ('report.csv',?'some,data,to,send\nanother,row,to,send\n')}

響應(yīng)

r.status_code

r.heards

r.cookies

跳轉(zhuǎn)

>>>?r?=?requests.get('http://httpbin.org/cookies/set?k2=v2&k1=v1')

>>>?r.url

'http://httpbin.org/cookies'

>>>?r.status_code200

>>>?r.history

[<Response [302]>]

r=requests.head('http://httpbin.org/cookies/set?k2=v2&k1=v1',allow_redirects=True)

requests.get('http://github.com',?timeout=0.001)


高級特性

來自?<http://docs.python-requests.org/en/master/user/advanced/#advanced>

session邑退,自動(dòng)保存cookies,可以設(shè)置請求參數(shù)劳澄,下次請求自動(dòng)帶上請求參數(shù)

s?=?requests.Session()

s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')

r?=?s.get('http://httpbin.org/cookies')

print(r.text)

# '{"cookies": {"sessioncookie": "123456789"}}'

session可以用來提供默認(rèn)數(shù)據(jù)地技,函數(shù)參數(shù)級別的數(shù)據(jù)會(huì)和session級別的數(shù)據(jù)合并,如果key重復(fù)秒拔,函數(shù)參數(shù)級別的數(shù)據(jù)將覆蓋session級別的數(shù)據(jù)莫矗。如果想取消session的某個(gè)參數(shù),可以在傳遞一個(gè)相同key砂缩,value為None的dict

s?=?requests.Session()

s.auth?=?('user',?'pass') #權(quán)限認(rèn)證

s.headers.update({'x-test':?'true'})

# both 'x-test' and 'x-test2' are sent

s.get('http://httpbin.org/headers',?headers={'x-test2':?'true'})

函數(shù)參數(shù)中的數(shù)據(jù)只會(huì)使用一次作谚,并不會(huì)保存到session中

如:cookies僅本次有效

r?=?s.get('http://httpbin.org/cookies',?cookies={'from-my':?'browser'})

session也可以自動(dòng)關(guān)閉

with?requests.Session()?as?s:

????????s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')

響應(yīng)結(jié)果不僅包含響應(yīng)的全部信息,也包含請求信息

r?=?requests.get('http://en.wikipedia.org/wiki/Monty_Python')

r.headers

r.request.headers

SSL證書驗(yàn)證

Requests可以為HTTPS請求驗(yàn)證SSL證書庵芭,就像web瀏覽器一樣食磕。要想檢查某個(gè)主機(jī)的SSL證書,你可以使用?verify?參數(shù):

>>>?requests.get('https://kennethreitz.com',?verify=True)

requests.exceptions.SSLError: hostname 'kennethreitz.com' doesn't match either of '*.herokuapp.com', 'herokuapp.com'

在該域名上我沒有設(shè)置SSL喳挑,所以失敗了。但Github設(shè)置了SSL:

>>>?requests.get('https://github.com',?verify=True)

<Response [200]>

對于私有證書滔悉,你也可以傳遞一個(gè)CA_BUNDLE文件的路徑給?verify?伊诵。你也可以設(shè)置REQUEST_CA_BUNDLE?環(huán)境變量。

>>>?requests.get('https://github.com',?verify='/path/to/certfile')

如果你將?verify?設(shè)置為False回官,Requests也能忽略對SSL證書的驗(yàn)證曹宴。

>>>?requests.get('https://kennethreitz.com',?verify=False)

<Response [200]>

默認(rèn)情況下,?verify?是設(shè)置為True的歉提。選項(xiàng)?verify?僅應(yīng)用于主機(jī)證書笛坦。

你也可以指定一個(gè)本地證書用作客戶端證書,可以是單個(gè)文件(包含密鑰和證書)或一個(gè)包含兩個(gè)文件路徑的元組:

>>>?requests.get('https://kennethreitz.com',?cert=('/path/server.crt',?'/path/key'))

<Response [200]>

響應(yīng)體內(nèi)容工作流

當(dāng)你進(jìn)行網(wǎng)絡(luò)請求后苔巨,響應(yīng)體會(huì)立即被下載版扩。你可以通過?stream?參數(shù)覆蓋這個(gè)行為,推遲下載響應(yīng)體直到訪問Response.content屬性:

tarball_url?=?'https://github.com/kennethreitz/requests/tarball/master'

r?=?requests.get(tarball_url,?stream=True)

此時(shí)僅有響應(yīng)頭被下載下來了侄泽,連接保持打開狀態(tài)礁芦,因此允許我們根據(jù)條件獲取內(nèi)容:

if? ?int(r.headers['content-length'])?<?TOO_LONG:

content?=?r.content

...

如果設(shè)置stream為True,請求連接不會(huì)被關(guān)閉悼尾,除非讀取所有數(shù)據(jù)或者調(diào)用Response.close柿扣。

可以使用contextlib.closing來自動(dòng)關(guān)閉連接:

import?requests

from?contextlib

import?closing

tarball_url?=?'https://github.com/kennethreitz/requests/tarball/master'

file?=?r'D:\Documents\WorkSpace\Python\Test\Python34Test\test.tar.gz'

with?closing(requests.get(tarball_url,?stream=True))?as?r:

? ? ? ??with?open(file,?'wb')?as?f:

for?data?in?r.iter_content(1024):

f.write(data)

Keep-Alive

?<http://docs.python-requests.org/en/master/user/advanced/>

同一會(huì)話內(nèi)你發(fā)出的任何請求都會(huì)自動(dòng)復(fù)用恰當(dāng)?shù)倪B接!

注意:只有所有的響應(yīng)體數(shù)據(jù)被讀取完畢連接才會(huì)被釋放為連接池闺魏;所以確保將?stream設(shè)置為?False?或讀取?Response?對象的?content?屬性未状。

流式上傳

Requests支持流式上傳,這允許你發(fā)送大的數(shù)據(jù)流或文件而無需先把它們讀入內(nèi)存析桥。要使用流式上傳司草,僅需為你的請求體提供一個(gè)類文件對象即可:

讀取文件請使用字節(jié)的方式艰垂,這樣Requests會(huì)生成正確的Content-Length

with?open('massive-body',?'rb')?as?f:

????????requests.post('http://some.url/streamed',?data=f)

>>>?requests.get('http://pizzabin.org/admin',?auth=PizzaAuth('kenneth'))

<Response [200]>

來自?<http://docs.python-requests.org/en/master/user/advanced/>

流式請求

r?=?requests.get('http://httpbin.org/stream/20',?stream=True)

for?line?in?r.iter_lines():

代理

import?requests

proxies?=?{

'http':?'http://10.10.1.10:3128',

'https':?'http://10.10.1.10:1080',}

requests.get('http://example.org',?proxies=proxies)

proxies?=?{'http':?'http://user:pass@10.10.1.10:3128/'}

超時(shí)

r?=?requests.get('https://github.com',?timeout=5)

r?=?requests.get('https://github.com',?timeout=(3.05,?27))

來自?<http://docs.python-requests.org/en/master/user/advanced/>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翻伺,隨后出現(xiàn)的幾起案子材泄,更是在濱河造成了極大的恐慌,老刑警劉巖吨岭,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拉宗,死亡現(xiàn)場離奇詭異,居然都是意外死亡辣辫,警方通過查閱死者的電腦和手機(jī)旦事,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來急灭,“玉大人姐浮,你說我怎么就攤上這事≡岵觯” “怎么了卖鲤?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長畴嘶。 經(jīng)常有香客問我蛋逾,道長,這世上最難降的妖魔是什么窗悯? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任区匣,我火速辦了婚禮,結(jié)果婚禮上蒋院,老公的妹妹穿的比我還像新娘亏钩。我一直安慰自己,他們只是感情好欺旧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布姑丑。 她就那樣靜靜地躺著,像睡著了一般辞友。 火紅的嫁衣襯著肌膚如雪彻坛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天踏枣,我揣著相機(jī)與錄音昌屉,去河邊找鬼。 笑死茵瀑,一個(gè)胖子當(dāng)著我的面吹牛间驮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播马昨,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼竞帽,長吁一口氣:“原來是場噩夢啊……” “哼扛施!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起屹篓,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疙渣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后堆巧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妄荔,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年谍肤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啦租。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荒揣,死狀恐怖篷角,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情系任,我是刑警寧澤恳蹲,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站俩滥,受9級特大地震影響阱缓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜举农,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望敞嗡。 院中可真熱鬧颁糟,春花似錦、人聲如沸喉悴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽箕肃。三九已至婚脱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間勺像,已是汗流浹背障贸。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吟宦,地道東北人篮洁。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像殃姓,于是被迫代替她去往敵國和親袁波。 傳聞我的和親對象是個(gè)殘疾皇子瓦阐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

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