## 請求
web應用給我們的感知都是以請求的方式呈現和運行的。
比如瀏覽器的表單提交,ajax請求,socket請求,服務端php的curl從一個服務器對另一個服務器的請求。
請求無處不在,請求支撐著我們日常的所有網絡應用,不論是app還是網站的,這些都是網絡應用,想要運行都離不開請求。
* * * * *
### TODO
ajax相應一定要等到服務器完全響應斷開連接才可以嗎,如果服務器不斷開連接,一直flush()推送呢,客戶端能源源不斷的收到信心嗎?
[php死循環代碼一直在運行? - 知乎](https://www.zhihu.com/question/46275054/answer/136984342)
[0714/2013 作業及預習+代碼+視頻 - 歷史視頻及代碼 自學it網-公益PHP培訓!](http://www.zixue.it/forum.php?mod=viewthread&tid=7820&extra=page%3D2%26filter%3Dtypeid%26typeid%3D35%26typeid%3D35)
[實現Comet(服務器推送)的兩種方式:長輪詢和http流_蔡武坤的博客-CSDN博客](https://blog.csdn.net/weixin_39181833/article/details/79723745)
> XMLHttpRequest 可以不斷監聽使用 xhr.readyState == 3
[xiasf - comet - Coding.net](https://coding.net/u/xiasf/p/comet/git)
> 原來ajax是服務端推送一次就斷開了,得再重新發起一次ajax,但是其阻塞了請求也是有意義的,而不是客戶端一個定時器每隔一個固定的時間去請求,這樣效率是最低的(不能預知,什么時候到達,請求什么時候返回,有可能同時,無法控制順序)。(**這樣也實現了【單例請求】,不會造成并發請求,“并發”更新UI的問題**)
[ajax、反向ajax、jsonp詳解 - CSDN博客](http://blog.csdn.net/kabulore/article/details/51910978)
[反向AJAX - CSDN博客](http://blog.csdn.net/lccone/article/details/7743886)
> Comet 這些技術不能大規模使用,因為占用了用于處理響應的進程(php-fpm),最終會導致并發能力越來越低,服務不可用的。
~~~
**實時信息很難從技術上解決。**
……
Comet(服務器推)
第二種主動式反向Ajax方法是Comet,這是一種基于HTTP長連接的服務器推動方式。客戶端向服務器發送請求后,服務器將數據通過response發送給客戶端,但并不會將此response關閉,而是一直通過response將最新的數據發送給客戶端瀏覽器,直到客戶端瀏覽器關閉。
~~~
>[danger] 服務器會阻塞請求,而不馬上斷開連接,而客戶端也能源源不斷的收到信息。
[30分鐘學會反向Ajax - 冷豪 - 博客園](http://blog.csdn.net/kabulore/article/details/51910978)
[網頁實時聊天之js和jQuery實現ajax長輪詢 - 枕邊書 - 博客園](https://www.cnblogs.com/zhenbianshu/p/4964095.html)

> #### 長輪詢的思想:
>
> 如圖:用AJAX發送詢問信息,服務器在沒有信息要返回的時候進入無限等待。由于AJAX異步的特性,PHP在服務器端執行等待不會影響到頁面的正常處理。一旦服務器查詢到返回信息,服務器返回信息,AJAX用回調函數處理這條信息,同時迅速再次發送一個請求等待服務器處理。
>
> 與 **傳統輪詢(簡易輪詢)** 相比,長輪詢在服務器沒的返回信息的時候進入等待,減少了普通輪詢服務器無數次的空回復。**可以這樣認為,長輪詢 使服務器每次的返回更有目的性,而不是盲目返回。**
[Comet技術詳解:基于HTTP長連接的Web端實時通信技術 - helloJackJiang - 博客園](https://www.cnblogs.com/imstudy/p/5696033.html)
~~~
“服務器推”是一種很早就存在的技術,以前在實現上主要是通過客戶端的套接口,或是服務器端的遠程調用。因為瀏覽器技術的發展比較緩慢,沒有為“服務器推”的實現提供很好的支持,在純瀏覽器的應用中很難有一個完善的方案去實現“服務器推”并用于商業程序。最近幾年,因為 AJAX 技術的普及,以及把 IFrame 嵌在“htmlfile“的 ActiveX 組件中可以解決 IE 的加載顯示問題,一些受歡迎的應用如 meebo,gmail+gtalk 在實現中使用了這些新技術;同時“服務器推”在現實應用中確實存在很多需求。因為這些原因,基于純瀏覽器的“服務器推”技術開始受到較多關注,Alex Russell(Dojo Toolkit 的項目 Lead)稱這種 **基于 HTTP 長連接、無須在瀏覽器端安裝插件的“服務器推”技術為“Comet”。**
使用 AJAX 實現“服務器推”與傳統的 AJAX 應用不同之處在于:
服務器端會阻塞請求直到有數據傳遞或超時才返回。
客戶端 JavaScript 響應處理函數會在處理完服務器返回的信息后,再次發出請求,重新建立連接。
當客戶端處理接收的數據、重新建立連接時,服務器端可能有新的數據到達;這些信息會被服務器端保存直到客戶端重新建立連接,客戶端會一次把當前服務器端所有的信息取回。
~~~
[feed留,單聊群聊,系統通知,狀態同步,到底是推還是拉?](https://mp.weixin.qq.com/s/54yEWWet9mFztv1fO_GTqQ)
> 大部分webim(特別是同時在線量大的)是http輪詢請求,后續撰文
[WEB即時通信最佳實踐](https://mp.weixin.qq.com/s/t1YkuDxUessq5bfials4gw)
* * * * *
### 實現單例請求
要用自循環/自調用方式來發出請求,而不能用定時器,這樣就能保證請求的順序性,保證每一時刻只有一個請求,請求中或等待響應。
偽代碼:
```javascript
function get(cb) {
$.ajax(data, function() {
cb(get);
});
}
get(get);
```
[為什么盡量別用 setInterval](https://mp.weixin.qq.com/s/8An8mfJQaursg4lDdoPayg)
> 無視網絡延遲:它仍然會按定時持續不斷地觸發請求,最終你的客戶端網絡隊列會塞滿Ajax調用。
* * * * *
### 夯住!
[http如何像tcp一樣實時的收消息?](https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651959605&idx=1&sn=21f25087bef3c3a966ef03b824365621&scene=4&rd2werd=1#wechat_redirect)
> 沒有消息到達的時候,**這個http消息連接將被夯住,不返回,由于http是短連接,這個http消息連接最多被夯住90秒**,就會被斷開(這是瀏覽器或者webserver的行為)
>
> webim通過http長輪詢可以保證消息的絕對實時性。這種實時性的保證不是通過增加輪詢頻率來保證的,而是通過夯住http消息連接來保證的
[網頁端收消息,究竟是推還是拉?](https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961175&idx=1&sn=4e74348e9e6c20aa11bf55949b24e20a&scene=0#wechat_redirect&rd2werd=1#wechat_redirect)
> 不像普通的“請求-響應”式HTTP請求,這個HTTP會被服務端夯住,直到有推送通知到達,或者超過約定的時間
[秒殺系統架構優化思路](https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651959391&idx=1&sn=fb28fd5e5f0895ddb167406d8a735548&scene=4&rd2werd=1#wechat_redirect)
> 用戶層面肯定是同步的(用戶的http請求是夯住的),服務層面可以同步可以異步。
[webim如何用輪詢保證消息絕對實時](https://mp.weixin.qq.com/s/VOSQLXBb7f1CZHj1dPRi3A)
> 沒有消息到達的時候,這個http消息連接將被夯住,不返回,由于http是短連接,這個http消息連接最多被夯住90秒,就會被斷開(這是瀏覽器或者webserver的行為)
[58到家數據庫30條軍規解讀](https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651959906&idx=1&sn=2cbdc66cfb5b53cf4327a1e0d18d9b4a&chksm=bd2d07be8a5a8ea86dc3c04eced3f411ee5ec207f73d317245e1fefea1628feb037ad71531bc&scene=4&rd2werd=1#wechat_redirect)
> 無主鍵的表刪除,在row模式的主從架構,會導致備庫夯住
* * * * *
### http
常見的就是http請求了,這是應用層的協議,之上鏈路層就是TCP、IP了。
我們用瀏覽器打開網頁就是http請求。
ajax也是http請求。
常用的curl也是http請求。
關于請求,我們需要知道的,請求包含哪些重要的信息:
- 請求地址
- 請求頭(協議頭信息,包含 Query String Parameters)
- body(Form Data)
- 數據編碼(發送數據的數據編碼,默認表單為 `Content-Type:application/x-www-form-urlencoded`)
- <del>數據格式(發送數據的數據格式)</del>
- 期望返回的數據格式(Accept)
注意:要分開理解數據編碼和字符編碼的概念。
Content-type: application/x-www-form-urlencoded; charset=UTF-8 (數據類型,數據編碼)
**Accept: \*/\*:** 客戶端可以使用Accept字段聲明自己可以接受哪些數據格式,也表示客戶端期望接受到什么類型的數據格式。
* * * * *
>[danger] 服務器端想要實現“異步”(返回數據給瀏覽器,并斷開與瀏覽器的連接,但是后端服務不停止,繼續運行),如果想實現這樣,服務端必須做一些處理才行,參見參考資料。
>[danger] 服務端完全響應完,瀏覽器才能收到200的狀態(只有瀏覽器和后端斷開連接了,ajax才能算是響應完成,不然一直加載的狀態,即使是有數據不斷flush輸送過來了)
* * * * *
### socket
待續
* * * * *
### 參考
[HTTP 協議超詳細講解](https://www.toutiao.com/a6506706975080841732/?tt_from=weixin&utm_campaign=client_share×tamp=1514976679&app=news_article&utm_source=weixin&iid=22069500288&utm_medium=toutiao_android&wxshare_count=1)
[HTTP,HTTP2.0,SPDY,HTTPS你應該知道的一些事 - WEB前端 - 伯樂在線](http://web.jobbole.com/87695/)
[專題 | JerryQu 的小站](https://imququ.com/post/series.html)
[Http協議的詳細總結](https://www.toutiao.com/a6516479528183792131/?tt_from=weixin&utm_campaign=client_share×tamp=1517277124&app=news_article&utm_source=weixin&iid=22069500288&utm_medium=toutiao_android&wxshare_count=1)
[http簡介](https://segmentfault.com/a/1190000009744707#articleHeader3)
[理解HTTP之Content-Type](https://segmentfault.com/a/1190000003002851)
[一文帶你了解 HTTP 黑科技](https://mp.weixin.qq.com/s/UWYe_3hcnClvsLvFJRBztA)
[jQuery Ajax 操作函數](http://www.w3school.com.cn/jquery/jquery_ref_ajax.asp)
[jQuery ajax - ajax() 方法](http://www.w3school.com.cn/jquery/ajax_ajax.asp)
[HTML \<form\> 標簽](http://www.w3school.com.cn/tags/tag_form.asp)
[文字編碼的那些事 – 人人網FED博客](https://fed.renren.com/2017/11/11/text-encode/)
[【底層原理】字符集和字符編碼(上)](https://mp.weixin.qq.com/s/DwsXrnq_-Mjw8hVekPZ4LQ)
[HTML URL 編碼](http://www.w3school.com.cn/tags/html_ref_urlencode.html)
[常用對照表 - Mime-Type](http://tool.oschina.net/commons)
[AJAX POST請求中參數以form data和request payload形式在servlet中的獲取方式](http://blog.csdn.net/mhmyqn/article/details/25561535)
[PHP獲取POST數據的三種方法](http://blog.csdn.net/jiao_fuyou/article/details/46314727)
[釘釘開放平臺文檔中心 - 建立連接](https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.uzGzqQ&treeId=385&articleId=104980&docType=1)
>[danger] POST請求請在HTTP Header中設置 Content-Type:application/json,否則接口調用失敗
[HTTP協議系列五—結合報文和Wireshark再談TCP三次握手](https://www.toutiao.com/a6508678486687744519/?tt_from=weixin&utm_campaign=client_share×tamp=1515523641&app=news_article&utm_source=weixin&iid=22069500288&utm_medium=toutiao_android&wxshare_count=1)
[HTTPS為什么安全? - CSDN博客](http://blog.csdn.net/xifeijian/article/details/54667989)
[技術輪回,靜態Web再度成為新趨勢?](https://mp.weixin.qq.com/s/JrsJiO_B8wJDjLqKN7awkQ)
[淘寶服務端高并發分布式架構演進之路](https://mp.weixin.qq.com/s/rAJfL6ykQYtBi0iTazptuQ)
[可用性高達5個9!支付系統高可用架構設計實戰](https://mp.weixin.qq.com/s/h8puL7jTE9YYOXO-mwWu3Q)
[被吹得天花亂墜的無服務器架構究竟是什么鬼?](https://mp.weixin.qq.com/s/2n_vYhnlP27FK9_cH8pZFQ)
[「ThinkPHP開發者周刊」第40期——高并發](https://mp.weixin.qq.com/s/yeleXMzL2SRYpyOmZv4XDQ)
> Laravelv6 發布?—— 引入部署平臺?Vapor
[如何將Web主頁性能提升十倍以上?](https://mp.weixin.qq.com/s/_DxXom8wI_eRlztci0Hj-w)
[詳解三次握手和四次揮手:遇到心動的女孩時,如何去把握?](https://mp.weixin.qq.com/s/cFiXzkelFaed50l_A0ummA)
[LVS四種實現模式詳解](https://mp.weixin.qq.com/s/1bXTMG7QtEQsoEjdHSwXsw)
[通俗易懂的Nginx工作原理](https://mp.weixin.qq.com/s/FBdasszBrVAqgLGXxuge2w)
[Linux驚群相關問題分析](https://mp.weixin.qq.com/s/ExRqSTBQ1_Z82SdgVUhOwg)
[揭開 asyncio 的神秘面紗 :從 hello world 說起](https://mp.weixin.qq.com/s/ltORoBfRowAR8iXYD3NDQw)
> asyncio 是用來編寫并發程序的庫。在爬蟲、客戶端應用等開發場景中, 我們經常會需要將多個網絡請求并行化來提高程序性能,而 asyncio 框架正好可以很方便的幫助我們實現這個需求。
[史上最污技術解讀,我竟然秒懂了](https://mp.weixin.qq.com/s/Ueh1QubRUkfDDP-ujAytUg)
[不要相信requests返回的text](https://mp.weixin.qq.com/s/ueDhUwAB1yipsOQsKEAqNQ)
[九種跨域方式實現原理](https://mp.weixin.qq.com/s/LV7qziMyrMt0_EJWo05qkA)
[如何給女朋友解釋為什么200M寬帶,打王者榮耀還是會卡?](https://mp.weixin.qq.com/s/4QFAcSY7Ode5NLijLwFUfA)
* * * * *
[訪問式的web服務(二)](http://www.hmoore.net/xiak/php-node/491960)
> 關于提交了關閉瀏覽器會出現的問題分析。
* * * * *
[Http 歷險記(上)](https://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513069&idx=1&sn=548c497c46c7c076145064a120c7c101&scene=21#wechat_redirect)
[Http歷險記(下)-- Struts的秘密](https://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513080&idx=1&sn=d24a4cdfc71412c581393d584fd91326&scene=21#wechat_redirect)
* * * * *
[AJAX POST請求中參數以form data和request payload形式在servlet中的獲取方式 - 癡人說夢 - CSDN博客](http://blog.csdn.net/mhmyqn/article/details/25561535)
~~~
2015-04-17后記:
最近在看書時才真正搞明白,服務器為什么會對表單提交和文件上傳做特殊處理,因為表單提交數據是名值對的方式,且Content-Type為application/x-www-form-urlencoded,而文件上傳服務器需要特殊處理,普通的post請求(Content-Type不是application/x-www-form-urlencoded)數據格式不固定,不一定是名值對的方式,所以服務器無法知道具體的處理方式,所以只能通過獲取原始數據流的方式來進行解析。
jquery在執行post請求時,會設置Content-Type為application/x-www-form-urlencoded,所以服務器能夠正確解析,而使用原生ajax請求時,如果不顯示的設置Content-Type,那么默認是text/plain,這時服務器就不知道怎么解析數據了,所以才只能通過獲取原始數據流的方式來進行解析請求數據。
~~~
[PHP獲取未知MIME類型(如text/xml)的請求數據 - 步知道 - CSDN博客](http://blog.csdn.net/luochuan/article/details/8282436)
~~~
PHP默認識別的數據類型是application/x-www.form-urlencoded標準的數據類型,我們在接收這種常規的數據類型的時候可以用全局數組$_REQUEST、$_POST或者$_GET來獲取客戶端請求的數據。
如果遇到未識別MIME類型的請求數據,如Content-Type=text/xml 類型或者直接POST一個JSON數據流,那么php要怎么獲取數據呢,PHP文檔里是這么描述的:
The RAW / uninterpreted HTTP POST information can be accessed with: $GLOBALS['HTTP_RAW_POST_DATA'] This is useful in cases where the post Content-Type is not something PHP understands (such as text/xml).
由于PHP默認只識別application/x-www.form-urlencoded標準的數據類型,因此,對型如text/xml的內容無法解析為$_POST數組,故保留原型,交給$GLOBALS['HTTP_RAW_POST_DATA'] ($HTTP_RAW_POST_DATA)來接收。
注意:此變量僅在碰到未識別 MIME 類型的數據時產生,$HTTP_RAW_POST_DATA 對于 enctype="multipart/form-data" 表單數據不可用。
~~~
[http頭部content-type與數據格式 - Trifling_的博客 - CSDN博客](http://blog.csdn.net/trifling_/article/details/53009500)
[HTTP協議詳解(真的很經典) - Hundre - 博客園](http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html)
[popen——php多進程利器 - CSDN博客](https://blog.csdn.net/leinchu/article/details/8191067)
[php中popen,exec,system,passthru到底有多大區別 - CSDN博客](https://blog.csdn.net/fishg/article/details/6138348)
[PHP 調用系統外部命令 system() exec() passthru() 和 popen() - CSDN博客](https://blog.csdn.net/wzhwho/article/details/6944019)
[php - popen如何實現多進程并發執行,循環里的pclose會等待進程完畢再進行下一次循環 - SegmentFault 思否](https://segmentfault.com/q/1010000007205306?_ea=1273185)
[php - popen函數調本地腳本并傳參數 - SegmentFault 思否](https://segmentfault.com/q/1010000006160351)
[使用fsockopen()實現異步調用PHP - CSDN博客](https://blog.csdn.net/lzr77/article/details/16369863)
> ……當 PHP 腳本正常地運行 NORMAL 狀態時,連接為有效。當客戶端中斷連接時,ABORTED 狀態的標記將會被打開。遠程客戶端連接的中斷通常是由用戶點擊 STOP 按鈕導致的。當連接時間超過 PHP 的時限(請參閱 set_time_limit() 函數)時,TIMEOUT 狀態的標記將被打開。……
[php fsockopen()方法,簡化,異步非阻塞調用 - CSDN博客](https://blog.csdn.net/qq_22823581/article/details/77712987)
[PHP觸發耗時腳本 - SegmentFault 思否](https://segmentfault.com/q/1010000004593434)
[PHP fsockopen函數問題,本腳本無阻塞觸發其他腳本失敗 - SegmentFault 思否](https://segmentfault.com/q/1010000004590173?_ea=660163)
[一文讀懂 HTTP 2.0 之服務器推送](https://mp.weixin.qq.com/s/YQCSJQpfnSENpzVpO5YAZg)
[【協議森林】從理論到實踐,全方位認識DNS(理論篇)](https://mp.weixin.qq.com/s/wzO1yUQGYXge7eTnZMqz0g)
[一個秒殺系統的設計思考](https://mp.weixin.qq.com/s/a_xiXBUbpIZ3HtuYvdYSPA)
* * * * *
[php://input - 簡單--生活 - 博客園](http://www.cnblogs.com/xiangxiaodong/archive/2012/11/07/2758685.html)
[PHP: php:// - Manual](http://php.net/manual/zh/wrappers.php.php)
[JS 服務器推送技術 WebSocket 入門指北](https://mp.weixin.qq.com/s/IRH0Y8wJjGKsydRWJ6KH7g)
[我遇過的最難的Cookie問題](https://mp.weixin.qq.com/s/UxySd528XMxsyD7GBC96EQ)
[Web 實時推送技術的總結](https://mp.weixin.qq.com/s/23unZJrMP9sVe5PTCApzGQ)
[網頁端收消息,究竟是推還是拉?](https://mp.weixin.qq.com/s/Z_xItxDUmUJO-W3bgYwb5Q)
> 不像普通的“請求-響應”式HTTP請求,這個HTTP會被服務端夯住,直到有推送通知到達,或者超過約定的時間
[系統通知,居然有人使用拉取?](https://mp.weixin.qq.com/s/cFtFQb4-9__Jqw6wTinftw)
> 拉 其實就是web訪問式服務了。
[雙機熱備的原理](https://mp.weixin.qq.com/s/mKkLJLr_XF_M-gkFr4jTyg)
[DNS原理入門](https://mp.weixin.qq.com/s/tROPiINO4Rj1pyNBsNhvlw)
[群消息已讀回執(這個diao),究竟是推還是拉?](https://mp.weixin.qq.com/s/fQhmrrJ0jypm_O3WFs7ftw)
> 聊天消息只需要記錄偏序,這條消息之前未讀,就可以,而通知類消息需要記錄每一條消息的閱讀狀態。
[群消息,究竟存1份還是多份?](https://mp.weixin.qq.com/s/1Pd0vhDu8lh9bpvKGQqLVA)
[網頁端收消息,究竟是推還是拉?](https://mp.weixin.qq.com/s/Z_xItxDUmUJO-W3bgYwb5Q)
[不懂RPC,休談微服務](https://mp.weixin.qq.com/s/dohsfOBkl2dGbOyQp1WpnQ)
~~~
服務端可以提供api調用,為什么還需要RPC呢?
作者
如果對性能要求較高,就可以使用RPC。
~~~
* * * * *
### php中實現異步的奇淫巧技
[php提前響應請求繼續執行代碼(偽異步)-仙士可博客,技術博客,php,技術分享](http://www.php20.cn/article/159)
[PHP主動斷開與瀏覽器的連接](http://blog.csdn.net/dodott/article/details/54629180)
[PHP 在 Nginx 下主動斷開連接 Connection Close 與 ignore_user_abort 后臺運行 - 蝸牛的專欄 - CSDN博客](http://blog.csdn.net/zhouzme/article/details/46886811)
[關于PHP連接處理中set_time_limit()、connection_status()和ignore_user_abort()深入解析 - 很多時候,你缺少的不是知識而是熱情 - CSDN博客](http://blog.csdn.net/jiao_fuyou/article/details/17138057)
[php輸出緩沖與http的聯系](http://mp.weixin.qq.com/s/DNbdCSj0RhalQGVyKTUnGA)
> 其實這樣**治標不治本**,因為fpm能力有限,你這兒占住了,那其他請求怎么辦,所以這不能真正解決問題。
>[tip] 這樣治標不治本,雖然前端收到完整的響應斷開連接了,但是后端服務并未就此結束,會一直占用當前php-fpm,這將導致系統的并發能力降低,任何時候都要考慮代碼的運行方式和運行環境,脫離這個前提,討論別的就是錯的,沒有意義。
[加速PHP的ECHO | 風雪之隅](http://www.laruence.com/2011/02/13/1870.html)
> 這也就引出了今天我要談的這個問題, 如何讓ECHO變快, 讓PHP的請求處理過程, 盡快結束…
>
> 最后要說明, 這樣做, 只是把原來ECHO的等待時間, 轉移給了Apache, 并沒有真正的減少客戶端獲取到內容的時間. 它只是加速了PHP的處理過程, 提前了PHP的退出時機, 從而能減少PHP對資源的占用時間, 間接增加資源的占用率.
[使用fastcgi_finish_request提高頁面響應速度 | 風雪之隅](http://www.laruence.com/2011/04/13/1991.html)
> 當PHP運行在FastCGI模式時,PHP FPM提供了一個名為fastcgi_finish_request的方法.按照文檔上的說法,此方法可以提高請求的處理速度,如果有些處理可以在頁面生成完后再進行,就可以使用這個方法.
>
> 這樣一下,像登錄的話,可能涉及很多復雜的東西可以我們可以放在”**偽后臺執行**(fastcgi_finish_request)”,
但是如果數量多的話, 就會出現超時的現象, 可以在頭部加入set_time_limit(0);
* * * * *
### 擴展
常規下,**php代碼寫出來的都是同步代碼**(即服務端代碼一行一行按順序執行,全部執行完畢,返回給瀏覽器,并斷開與瀏覽器的連接,也就是 **服務端完全響應完,瀏覽器才能收到200的狀態**)。
但是通過一些技巧,可以實現所謂的異步,上面有講到。
[guzzle/guzzle](https://github.com/guzzle/guzzle) 里面有異步的curl請求,這是怎么做到的呢?
```php
// Send an asynchronous request.
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
$promise = $client->sendAsync($request)->then(function ($response) {
echo 'I completed! ' . $response->getBody();
});
$promise->wait();
```
有時間再去研究一下,不過目前猜測很可能就是通過上面說的那種技巧實現的。
猜測也不對,curl是在服務端發起的,這種技巧應該不行的。
[PHP實現執行定時任務的幾種思路詳解 - Web烤貓 - SegmentFault](https://segmentfault.com/a/1190000002955509)
> fsockopen可以實現在請求訪問某個文件時,不必獲得返回結果就繼續往下執行程序,這是和curl通常用法不一樣的地方,**我們在使用curl訪問網頁時,一定要等curl加載完網頁后,才會執行curl后面的代碼,雖然實際上curl也可以實現“非阻塞式”的請求,但是比fsockopen復雜的多,所以我們優先選擇fsockopen**,fsockopen可以在規定的時間內,比如1秒鐘以內,完成對訪問路徑發出請求,完成之后就不管這個路徑是否返回內容了,它的任務就到這里結束,可以繼續往下執行程序了。利用這個特性,我們在正常的程序流中加入fsockopen,對上面我們創建的這個定時任務php的地址發出請求,即可讓定時任務在后臺執行。如果上面這個php的url地址是www.yourdomain.com/script.php,那么我們在編程中,可以這樣:
[PHP非阻塞模式 | 塵緣的博客](http://www.4wei.cn/archives/1002336)
[簡單介紹PHP非阻塞模式_php實例_腳本之家](http://www.jb51.net/article/80381.htm)
[PHP的非阻塞或并行請求實現方式 - 簡書](https://www.jianshu.com/p/7a15f974657d)
[php非阻塞訪問url 解析socket阻塞與非阻塞,同步與異步 - 橙虛緣空間 - CSDN博客](http://blog.csdn.net/qq43599939/article/details/50570098)
[PHP異步:在PHP中使用 fsockopen curl 實現類似異步處理的功能 - Web烤貓 - SegmentFault 思否](https://segmentfault.com/a/1190000002982448)
[PHP HTTP客戶端-Guzzle原理解析](https://mp.weixin.qq.com/s/Qr1mCwrpnu2cOPuJP6ID5w)
[PHP中用簡單征服復雜,fsockopen函數實現多進程并發](https://www.toutiao.com/a6389852540971892994/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1×tamp=1538709320&app=news_article_lite&utm_source=weixin&iid=33124962994&utm_medium=toutiao_android&group_id=6389852540971892994)
> fsockopen 無阻塞并發調用,精髓在于是無阻塞調用,不用阻塞等調用返回。(操作的同時向任務發送fsockopen無阻塞請求,并帶上載荷,就可以替代MQ了。)
[除了芯片 ,還有一種神秘的技術曾被國外壟斷](https://mp.weixin.qq.com/s/5s9D1Bv8Ehc8MPTDieVyQw)(硬件層的負載均衡方案)
[如何給女朋友解釋什么是分布式和集群?文末有驚喜!](https://mp.weixin.qq.com/s/d6d1fTj1qKVFqZ8PXVq6NQ)
[炫技,從 12.67s 到 1.06s 的網站性能優化實戰](https://mp.weixin.qq.com/s/D43XIqa7BrSEzE4ISXxWmg)
[“12306”的架構到底有多牛逼?](https://mp.weixin.qq.com/s/oqjbW4ylAwVm5iUWsuJiEQ)
[Nginx負載均衡健康檢測,你了解過嗎?](https://mp.weixin.qq.com/s/wAJpvlyOtRiHQLkMxjp5Ow)
> 這樣就不會大家集中去監聽一個資源了(監聽資源/節點),避免了爭搶問題,同時確定了順序性,不可謂不高明啊
[【系統架構】僅需這一篇,吃透「負載均衡」妥妥的](https://mp.weixin.qq.com/s/SO1ZLSPaRkk8WwUl9u-JPA)
[咖啡館的故事:FTP, RMI , XML-RPC, SOAP, REST一網打盡](https://mp.weixin.qq.com/s/OXIFJGSozoRWNaLhnD0wxw)
[Varnish_百度百科]([https://baike.baidu.com/item/Varnish/10219137?fr=aladdin](https://baike.baidu.com/item/Varnish/10219137?fr=aladdin))
> Varnish是一款高性能的開源HTTP加速器,挪威最大的在線報紙 Verdens Gang 使用3臺Varnish代替了原來的12臺Squid,性能比以前更好。
[【系統架構】分布式之緩存擊穿(上)](https://mp.weixin.qq.com/s/MXM2gtMVk5ViyragLK_1Tw)
* * * * *
**思考**
如果實現了所謂的異步,**即快速返回結果給瀏覽器,并斷開連接,瀏覽器收到http狀態200**,但此時后端還沒結束,還在繼續執行,那這樣的話就不需要了MQ了啊,替代了MQ的功能啊(**本來立即要做的事情,但是由于事情太費時間,前臺不能等,而且這個事情的實時性要求不是那么高,并不是說一定要你同步做,所以放到隊列里面,讓另一個人去做**),當然這里所說的隊列只是MQ中最普通的一種隊列模式,MQ不只是這一種隊列模式,還有延時隊列等等。
>[danger] **異步/MQ:[調用方] 不依賴于 [此邏輯]的執行。(主要目的在于[解耦](https://www.zhihu.com/question/20278169),讓合適的人干合適的事情,并且相互之間沒有依賴)**
>[danger] 同步處理主要的任務,異步處理非緊要的事,并且耗時的事,但是又不可能全部異步沒有同步,同步就像一個樹的根和主干,異步就是主干上的一些分支,葉子。異步要做的事也是從同步來的,同步快速保存數據。同步是根,異步是葉。這就是他們在軟件開發中的關系。
[深入NGINX:nginx高性能的實現原理 - panda521 - 博客園](https://www.cnblogs.com/chenjfblog/p/8715580.html)
[Nginx+Php-fpm運行原理詳解 - CSDN博客](https://blog.csdn.net/u013474436/article/details/52972699)
>[danger] 不過這樣就沒意義了,隊列主要的思想就是異步,不阻塞當前響應,讓一些耗時任務可以堆積在**Broker(中間/第三方系統)** 中等待,這樣不會影響系統的服務能力,而如果這樣做,雖然表面看起來效果和隊列一樣的,但是請求多了,php-fpm處理的連接是有限的,會導致很多請求沒辦法響應,都阻塞著,最終超時。嚴重影響系統的并發服務能力。
> 這樣治標不治本,會占用php-fpm(新的請求也是打在其他php-fpm上),任何時候都要考慮代碼的運行方式和運行環境,脫離這個前提,討論別的就是錯的,沒有意義。
>[tip] fsockopen 雖然能實現所謂“異步”的調用,看似在功能上可以完全替代MQ,**先不論這樣會繼續占用php-fpm進程(新的請求也是打在其他php-fpm上)**,單從工程上來說,**這樣的實現不能體現服務/編碼的工程化**,違背了開發的模塊化,所以是不提倡這樣使用的,實際生產中不能這樣寫代碼。
**這種方式只是一種偽多進程并發,偽異步,偽后臺執行。**
(知識點:并發,并行,隊列,異步)
* * * * *
[淘寶詳情頁的 BigRender 優化與存放大塊 HTML 內容的最佳方式](https://lifesinger.wordpress.com/2011/09/23/bigrender-for-taobao-item/)
~~~
對于復雜頁面,為了將用戶關注的內容盡可能快渲染出來,至少有兩種方式:
一、Facebook 的 BigPipe 方式。先輸出頁面整體布局,然后逐步輸出腳本塊,一邊輸出一邊執行,將內容渲染回頁面布局中。這樣可以讓服務端的運算、網絡傳輸和瀏覽器端的渲染變成并行。BigPipe 最主要解決的問題是服務端的運算時間,當服務端的運算時間大于 300 ~ 500ms 時才能體現出優勢。當服務端響應非常快(小于 100ms),BigPipe 退化為下面要講的 BigRender.
二、淘寶商品詳情頁的 BigRender 方式。淘寶的商品詳情頁,服務端平均響應時間為 52ms, 采用 BigPipe chunked 輸出意義不大。這次優化主要在瀏覽器端。頁面下載完畢后,要經過 Tokenization — Tree Construction — Rendering. 要讓首屏盡快出來,得給瀏覽器減輕渲染首屏的工作量。可以從兩方面入手:
減少 DOM 節點數。節點數越少,意味著 Tokenization, Rendering 等操作耗費的時間越少。(對于典型的淘寶商品詳情頁,經測試發現,每增加一個 DOM 節點,會導致首屏渲染時間延遲約 0.5ms.)
減少腳本執行時間。腳本執行和 UI Update 共享一個 thread, 腳本耗的時間越少,UI Update 就能越發提前。
~~~
Facebook 的 BigPipe 也是一種比較好的方式,做法是是先push出頁面的結構,然后一邊計算一邊輸出頁面的填充內容,當然這個內容只能通過輸出js腳本填充了。
* * * * *
[淺談服務器端推送技術](http://www.toutiao.com/i6473074659892920845/)
原來服務器和瀏覽器不斷開,ajax也是可以收到數據的,不一定要是這個狀態:`xhr.readyState==4 && xhr.status==200`
~~~
if (xhr.readyState==4 && xhr.status==200)
{
var str =xhr.responseText;
}
~~~
~~~
流
流是通過HTTP流實現的。不同與長輪詢,它在頁面的整個生命周期內只能使用一個HTTP連接。瀏覽器向服務器發送一個請求,服務器保持連接打開,然后周期性地向瀏覽器發送數據。
服務器端實現:
<?php
$i = 0;
while(true){
echo "Number is $i";
flush();
sleep(10);
$i++;
}
瀏覽器端實現:
function createStreamingClient(url,progress,finished){
var xhr = new XMLHttpRequest(), received = 0;
xhr.open("get",url,true);
xhr.onreadystatechange = function(){
var result;
if(xhr.readyState == 3){ //只取得最新數據并調整計數器
result = xhr.responseText.substring(received);
received += result.length; //用新數據調用progress回調函數
progress(result);
}else if(xhr.readyState == 4){
finished(xhr.responseText);
}
};
xhr.send(null);
return xhr;
}
~~~
* * * * *
### 假異步?取代普通隊列?
php后端可以發送斷開頭后再繼續執行,甚至前端也可以不用等到http狀態200,那這么來看的話,就可以很簡單的將耗時的操作“異步”了啊,這樣就可以完全不需要普通的隊列了啊。
完全可以用這種方式替代普通的隊列服務了啊。其實這種作弊的方式,只適用于訪問式web,服務端作為被調用方,這其實不算真正的異步,只是欺騙調用方而已。真正的異步是調用方執行異步代碼不會阻塞調用方本身,等異步代碼執行玩后會自動返回結果給調用方。異步其實是一種程序模型。
只要調用方不需要立即得到結果的調用都可以異步,語言調用運行時得到結果的也不能異步,只能同步阻塞調用。
我們平常寫代碼的結構和方式,就是自上而下的同步結構,同步代碼。這也是我們正常的認知。
而異步代碼往往需要執行環境的支持或者特殊的進程實現,比如瀏覽器中的js異步是靠事件循環和定時器來實現的,這是瀏覽器這個宿主環境自帶的功能。有一些則需要多個進程配合,比如后臺的常駐服務,多工人進程等,比如 [Swoole](https://www.swoole.com/)。
**從沙子到應用**
不管理念和概念多么先進,抽象出來的技術多么復雜,其實底層實現都是樸素的,本質都是一樣的(返璞歸真),以不變應萬變,要知道計算機就是抽象的。一層一層的往上抽象、封裝,直至到最上面的一層,即:呈現在我們眼前的應用。
所有的問題都可以通過抽象,分層設計來描述和解決。
但是注意所有東西都是相對的,比如相對于機器碼來說,編程語言就是應用層了,而相對于底層協議,我們編寫的業務代碼才是屬于應用層。
* * * * *
last update:2018-1-5 18:51:09
- 開始
- 公益
- 更好的使用看云
- 推薦書單
- 優秀資源整理
- 技術文章寫作規范
- SublimeText - 編碼利器
- PSR-0/PSR-4命名標準
- php的多進程實驗分析
- 高級PHP
- 進程
- 信號
- 事件
- IO模型
- 同步、異步
- socket
- Swoole
- PHP擴展
- Composer
- easyswoole
- php多線程
- 守護程序
- 文件鎖
- s-socket
- aphp
- 隊列&并發
- 隊列
- 講個故事
- 如何最大效率的問題
- 訪問式的web服務(一)
- 訪問式的web服務(二)
- 請求
- 瀏覽器訪問阻塞問題
- Swoole
- 你必須理解的計算機核心概念 - 碼農翻身
- CPU阿甘 - 碼農翻身
- 異步通知,那我要怎么通知你啊?
- 實時操作系統
- 深入實時 Linux
- Redis 實現隊列
- redis與隊列
- 定時-時鐘-阻塞
- 計算機的生命
- 多進程/多線程
- 進程通信
- 拜占庭將軍問題深入探討
- JAVA CAS原理深度分析
- 隊列的思考
- 走進并發的世界
- 鎖
- 事務筆記
- 并發問題帶來的后果
- 為什么說樂觀鎖是安全的
- 內存鎖與內存事務 - 劉小兵2014
- 加鎖還是不加鎖,這是一個問題 - 碼農翻身
- 編程世界的那把鎖 - 碼農翻身
- 如何保證萬無一失
- 傳統事務與柔性事務
- 大白話搞懂什么是同步/異步/阻塞/非阻塞
- redis實現鎖
- 淺談mysql事務
- PHP異常
- php錯誤
- 文件加載
- 路由與偽靜態
- URL模式之分析
- 字符串處理
- 正則表達式
- 數組合并與+
- 文件上傳
- 常用驗證與過濾
- 記錄
- 趣圖
- foreach需要注意的問題
- Discuz!筆記
- 程序設計思維
- 抽象與具體
- 配置
- 關于如何學習的思考
- 編程思維
- 談編程
- 如何安全的修改對象
- 臨時
- 臨時筆記
- 透過問題看本質
- 程序后門
- 邊界檢查
- session
- 安全
- 王垠
- 第三方數據接口
- 驗證碼問題
- 還是少不了虛擬機
- 程序員如何談戀愛
- 程序員為什么要一直改BUG,為什么不能一次性把代碼寫好?
- 碎碎念
- 算法
- 實用代碼
- 相對私密與絕對私密
- 學習目標
- 隨記
- 編程小知識
- foo
- 落盤
- URL編碼的思考
- 字符編碼
- Elasticsearch
- TCP-IP協議
- 碎碎念2
- Grafana
- EFK、ELK
- RPC
- 依賴注入
- 科目一
- 開發筆記
- 經緯度格式轉換
- php時區問題
- 解決本地開發時調用遠程AIP跨域問題
- 后期靜態綁定
- 談tp的跳轉提示頁面
- 無限分類問題
- 生成微縮圖
- MVC名詞
- MVC架構
- 也許模塊不是唯一的答案
- 哈希算法
- 開發后臺
- 軟件設計架構
- mysql表字段設計
- 上傳表如何設計
- 二開心得
- awesomes-tables
- 安全的代碼部署
- 微信開發筆記
- 賬戶授權相關
- 小程序獲取是否關注其公眾號
- 支付相關
- 提交訂單
- 微信支付筆記
- 支付接口筆記
- 支付中心開發
- 下單與支付
- 支付流程設計
- 訂單與支付設計
- 敏感操作驗證
- 排序設計
- 代碼的運行環境
- 搜索關鍵字的顯示處理
- 接口異步更新ip信息
- 圖片處理
- 項目搭建
- 閱讀文檔的新方式
- mysql_insert_id并發問題思考
- 行鎖注意事項
- 細節注意
- 如何處理用戶的輸入
- 不可見的字符
- 抽獎
- 時間處理
- 應用開發實戰
- python 學習記錄
- Scrapy 教程
- Playwright 教程
- stealth.min.js
- Selenium 教程
- requests 教程
- pyautogui 教程
- Flask 教程
- PyInstaller 教程
- 蜘蛛
- python 文檔相似度驗證
- thinkphp5.0數據庫與模型的研究
- workerman進程管理
- workerman網絡分析
- java學習記錄
- docker
- 筆記
- kubernetes
- Kubernetes
- PaddlePaddle
- composer
- oneinstack
- 人工智能 AI
- 京東
- pc_detailpage_wareBusiness
- doc
- 電商網站設計
- iwebshop
- 商品規格分析
- 商品屬性分析
- tpshop
- 商品規格分析
- 商品屬性分析
- 電商表設計
- 設計記錄
- 優惠券
- 生成唯一訂單號
- 購物車技術
- 分類與類型
- 微信登錄與綁定
- 京東到家庫存系統架構設計
- crmeb
- 命名規范
- Nginx https配置
- 關于人工智能
- 從人的思考方式到二叉樹
- 架構
- 今日有感
- 文章保存
- 安全背后: 瀏覽器是如何校驗證書的
- 避不開的分布式事務
- devops自動化運維、部署、測試的最后一公里 —— ApiFox 云時代的接口管理工具
- 找到自己今生要做的事
- 自動化生活
- 開源與漿果
- Apifox: API 接口自動化測試指南