## 请求
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)
![](http://cdn.aipin100.cn/18-7-2/22155054.jpg)
> #### 长轮询的思想:
>
> 如图:用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服务(二)](https://www.kancloud.cn/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 接口自动化测试指南