热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[聊一聊系列]聊一聊网页的分段传输与渲染那些事儿

欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面(不仅仅是代码):https:s

欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面(不仅仅是代码):
https://segmentfault.com/blog...

这一节,请跟随笔者聊一聊,网页的分段传输与渲染,用一些非常规手段优化我们的网站响应速度。

1 CHUNKED编码

1.1 传统的渲染方法

1.1.1 传统的渲染方法怎么做?

按照常理,我们渲染一张网页,必定是网页全部拼装完毕,然后生成HTML字符串,传送至客户端。这也意味着,如果一张网页处理的有快有慢的话,必须串行等到所有的逻辑都处理完毕。后端才能进行返回。(这也是我们目前网页的一般逻辑)。如下面的例子,三个很慢的读数据操作,均执行完毕后,才传送渲染页面。渲染效果如图1.1.1,15s之后才传送并渲染出页面:
normal.php

function getOneData() {usleep(5000000);return '我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据';
}$var1 = getOneData();function getTwoData() {usleep(5000000);return '是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据';
}
$var2 = getTwoData();function getThreeData() {usleep(5000000);return '我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据';
}
$var3 = getThreeData();// 渲染模板并输出
include('./normal.html.php');

normal.html.php


1.
2.
3.

clipboard.png
图1.1.1

上述例子,在本文后github中的normal文件夹中。

1.1.2 传统的渲染方法有哪些弊端?

如上所示,我们能看到,直出的网页中,存在着后端数据串行,互相等待的尴尬局面。这也为我们后续的优化埋下了伏笔。

1.2 分段传输

1.2.1 何为分段传输?

http1.1中引入了一个http首部,Transfer-Encoding:chunked。这个首部标识了实体采用chunked编码传输,chunked编码可以将实体分块儿进行传输,并且chunked编码的每一块内容都会自标识长度。这给了web开发者一个启示,如果需要多个数据,而多个数据均返回较慢的话。可以处理完一块就返回一块,让浏览器尽早的接收到html,可以先行渲染。

1.2.2 如何分段传输?

既然知道了我们可以将网页一块儿一块儿的传送,那么我们就可以将上面的网页进行改造,拿好一块儿需要的数据,便渲染一块儿,无需等待,而模板方面,自然也要拆分为三段,供服务端拿一块儿的模板,就渲染一块儿出去,效果如图1.2.2.1。
normal.php

function getOneData() {usleep(5000000);return '我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出>的第一个数据我是取出的第一个数据我是取出的第一个数据我是取出的第一个数据';
}
// 取出第一块儿的数据
$var1 = getOneData();
// 渲染第一块儿
include('./normal1.html.php');
//刷新到缓冲区,渲染第一份儿模板,传送到客户端
ob_flush();
flush();function getTwoData() {usleep(5000000);return '我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出>的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出>的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出>的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出>的第二个数据我是取出的第二个数据我是取出的第二个数据我是取出的第二个数据';
}
// 取出第二块儿的数据
$var2 = getTwoData();
// 渲染第二块儿
include('./normal2.html.php');
//刷新到缓冲区,渲染第二份儿模板,传送到客户端
ob_flush();
flush();function getThreeData() {usleep(5000000);return '我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出>的第三个数据我是取出的第三个数据我是取出的第三个数据我是取出的第三个数据';
}
// 获取第三块儿的数据
$var3 = getThreeData();
// 渲染第三块儿
include('./normal3.html.php');
// 将第三份儿的模板,传送到客户端
ob_flush();
flush();

normal1.html.php


1.

normal2.html.php

2.

normal3.html.php

3.

clipboard.png
图1.2.2.1
上述例子,在本文后github中的chunked文件夹中。

对比图图1.1.1与图1.2.2.1我们可以发现,虽然最后总的处理时长不变,但是采用了分段输出的网页,可以尽早的将一段HTML渲染到客户端,这样用户可以使用先到达的部分。另一方面,尽早的页面反馈,也可以减少用户等待的焦躁情绪。综上,使用此种优化方法,可以提速网页的渲染速度。

1.2.3 分段传输小TIPs

我们代码虽然如上所述,但是读者尝试的时候可能会发现,并没有什么效果。和我截图并不一样,还是等到15s后一起渲染出来了。这里要提醒大家一下,可能是由于nginx配置的原因。如果使用的是nginx做server的话,要使用如下配置才能看到效果。

http {....fastcgi_buffer_size 1k; fastcgi_buffers 16 1k; gzip off;....
}

其实读者们可以这么理解上面的配置,nginx会在攒够一块儿缓冲区的量后,可以将一块儿数据发出去。上面我们配置了fastcgi_buffers 16 1k; 就是16块儿,大小为1K的缓存。

我们的数据量太小了,连默认的一块儿缓冲区都填不满,没法看到分块儿发送的效果,所以这里我们将缓冲区给调小为1K,这样就能1K为单位分块儿,1K一发,体现出实验效果了。笔者这里建议做实验的时候,最好把gzip给关了,因为,咱们做实验的时候数据量不大,实际使用中建议chunked与gzip均开启(如图1.2.3.1,如果量比较大的话,gzip与chunked均开启使用效果更佳哦~~~)。
clipboard.png
图1.2.3.1

1.2.4 分段传输适用场景

当页面的某些后端处理比较耗时的时候,可以试试采用分段传输,可以渲染一部分,就发送一部分到客户端,虽然总时长不变,但是浏览器在全部传输完之前不会处于干等状态。可以尽早的渲染并给予用户反馈。

2 BIGPIPE

2.1 分段传输的局限

刚刚笔者和读者们一起做了分段传输的实验,思路是基于读者们想展示的网页也是上快下慢的。可是读者们有没有想过,如果整个网页中,最快的是下方,而最慢的是上方呢?这样我们就无法利用分段传输的优势了吗?如图2.1.1,整个页面依旧是被最慢的第一部分数据渲染给hold住了。而后两块儿渲染较快,完全可以先传输过来。

// 获取第一块儿数据最慢
function getOneData() {usleep(2000000);$str &#61; &#39;&#39;; for ($i &#61; 0; $i <500; $i&#43;&#43;) {$str .&#61; &#39;我是取出的第一个数据&#39;;} return $str;
}$var1 &#61; getOneData();
// 渲染第一块儿
include(&#39;./normal1.html.php&#39;);
ob_flush();
flush();// 获取第二块儿数据较快
function getTwoData() {$str &#61; &#39;&#39;; for ($i &#61; 0; $i <500; $i&#43;&#43;) {$str .&#61; &#39;我是取出的第二个数据&#39;;} return $str;
}
$var2 &#61; getTwoData();
// 渲染第二块儿
include(&#39;./normal2.html.php&#39;);
ob_flush();
flush();// 获取地三块儿数据也较快
function getThreeData() {$str &#61; &#39;&#39;; for ($i &#61; 0; $i <500; $i&#43;&#43;) {$str .&#61; &#39;我是取出的第三个数据&#39;;} return $str;
}
$var3 &#61; getThreeData();
// 渲染第三块儿
include(&#39;./normal3.html.php&#39;);
ob_flush();
flush();

clipboard.png
图2.1.1

上述例子&#xff0c;在本文后github中的bigpipprepare文件夹中。

2.2 解决分段传输顺序的问题

看完上述描述&#xff0c;读者们肯定在想&#xff0c;如果能把最慢的部分放置于底部传过来就好了。于是有了一种加载思路&#xff0c;便是使用js回填的方式&#xff0c;先将左边最慢的部分架空&#xff0c;然后在底部写上js回填。这样不就可以先渲染相对较快的右侧两块儿了么。如图2.2.1
后端可以先渲染快的模板&#xff0c;然后再渲染最慢的模板。

// 渲染第一块儿的架子&#xff0c;还未获取内容
include(&#39;./normal1.html.php&#39;);
ob_flush();
flush();// 获取第二块儿数据较快
function getTwoData() {$str &#61; &#39;&#39;; for ($i &#61; 0; $i <50; $i&#43;&#43;) {$str .&#61; &#39;我是取出的第二个数据&#39;;} return $str;
}
$var2 &#61; getTwoData();// 渲染第二块儿
include(&#39;./normal2.html.php&#39;);
ob_flush();
flush();// 获取地三块儿数据也较快
function getThreeData() {$str &#61; &#39;&#39;; for ($i &#61; 0; $i <70; $i&#43;&#43;) {$str .&#61; &#39;我是取出的第三个数据&#39;;} return $str;
}
$var3 &#61; getThreeData();
// 渲染第三块儿
include(&#39;./normal3.html.php&#39;);
ob_flush();
flush();// 获取第一块儿数据最慢
function getOneData() {usleep(2000000);$str &#61; &#39;&#39;; for ($i &#61; 0; $i <50; $i&#43;&#43;) {$str .&#61; &#39;我是取出的第一个数据&#39;;} return $str;
}
$var1 &#61; getOneData();
// 渲染回填第一块儿
include(&#39;./normal4.html.php&#39;);
ob_flush();
flush();

normal1.html.php


normal2.html.php

2.

normal3.html.php

3.

normal4.html.php


clipboard.png
图2.2.1
如上图&#xff0c;可以看到49ms的时候&#xff0c;就已经渲染出来了右侧两块儿&#xff0c;2S的时候&#xff0c;左侧也渲染出来了。

上述例子&#xff0c;在本文后github中的bigpipe文件夹中。

2.3 回填思路的扩展与并行化

我们刚刚做了一个实验&#xff0c;是将耗时最慢的块儿放在底部。然而&#xff0c;事实情况是&#xff0c;如果你也不知道哪块儿慢了呢&#xff1f;或者是&#xff0c;你的几块儿数据区块儿是并行的呢&#xff1f;出于刚刚的经验&#xff0c;我们可以把页面上所有的块儿都架空&#xff0c;然后并行渲染&#xff0c;谁快谁就先渲染回填js。这样就可以达到并行且先到先渲染的目的了。我这里做了个php并行取并回填的实验&#xff0c;如图2.3.1&#xff0c;可以看到&#xff0c;中间红色的虽然被阻塞&#xff0c;但是框架先行渲染出来了所有的内容均是空的。绿色最快&#xff0c;先行回填渲染了出来&#xff0c;蓝色稍慢&#xff0c;也跟着渲染了出来&#xff0c;最后红色完毕&#xff0c;回填渲染结束了。
并行渲染的PHP(normal.php)

function asyncRequest($host, $url, $port&#61;8082, $conn_timeout&#61;30, $rw_timeout&#61;86400) {$errno &#61; &#39;&#39;; $errstr &#61; &#39;&#39;; $fp &#61; fsockopen($host, $port, $errno, $errstr, $conn_timeout);if (!$fp) {echo "Server error:$errstr($errno)";return false;} stream_set_timeout($fp, $rw_timeout);stream_set_blocking($fp, false);$rq &#61; "GET $url HTTP/1.0\r\n";$rq .&#61; "Host: $host\r\n";$rq .&#61; "Connect: close\r\n\r\n";fwrite($fp, $rq);return $fp;
}function asyncFetch(&$fp) {if ($fp &#61;&#61;&#61; false) return false;if (feof($fp)) {fclose($fp);$fp &#61; false;return false;} return fread($fp, 10000);
}$fp1 &#61; asyncRequest(&#39;localhost&#39;, &#39;/bigpipeparal/data1.php&#39;);
$fp2 &#61; asyncRequest(&#39;localhost&#39;, &#39;/bigpipeparal/data2.php&#39;);
$fp3 &#61; asyncRequest(&#39;localhost&#39;, &#39;/bigpipeparal/data3.php&#39;);include(&#39;normal_frame.html.php&#39;);
ob_flush();
flush();
while (true) {sleep(1);$r1 &#61; asyncFetch($fp1);$r2 &#61; asyncFetch($fp2);$r3 &#61; asyncFetch($fp3);//谁快谁先渲染并flush刷出if ($r1 !&#61; false) {preg_match(&#39;/\|(.&#43;)\|/i&#39;, $r1, $res);$var1 &#61; $res[1];include(&#39;normal1.html.php&#39;);}if ($r2 !&#61; false) {preg_match(&#39;/\|(.&#43;)\|/i&#39;, $r2, $res);$var2 &#61; $res[1];include(&#39;normal2.html.php&#39;);}if ($r3 !&#61; false) {preg_match(&#39;/\|(.&#43;)\|/i&#39;, $r3, $res);$var3 &#61; $res[1];include(&#39;normal3.html.php&#39;);}if ($r1 &#61;&#61; false && $r2 &#61;&#61; false && $r3 &#61;&#61; false) {break;}ob_flush();flush();
}

主框架的模板&#xff0c;架空&#xff0c;等待回填。normal_frame.html.php



具体回填模板&#xff0c;normal1.html.php/normal2.html.php/normal3.html.php

clipboard.png
图2.3.1

上述例子&#xff0c;在本文后github中的bigpipeparal文件夹中。

2.4 为什么不用ajax&#xff1f;

相信读着在此处会有疑问&#xff0c;为什么慢的数据&#xff0c;不用ajax去请求呢&#xff1f;这样模板框架也能尽早的渲染出来。ajax毕竟是请求。相信很多读着也有这样的经历&#xff0c;后端处理如果遇到了瓶颈&#xff0c;那么有的时候我们会选择同步页面渲染完之后&#xff0c;再发个请求去获取后端数据。但是笔者认为&#xff0c;这样做有一定弊端&#xff1a;
1、ajax毕竟是个请求&#xff0c;请求就要有连接&#xff0c;要有解析等过程。
2、服务端和客户端都会有闲的时候&#xff0c;发送ajax之前服务端闲&#xff0c;发送ajax出去之后&#xff0c;浏览器又闲着了。
所以&#xff0c;我们使用bigpipe的方式还是比多发送一个ajax有优势的。

3 分段传输与bigpipe适用场景

3.1 分段传输的适用场景

笔者总结了一些使用分块儿传输比较合适的场景
1 前端需要尽早传输head中的一些css/js外联文件的情况下(可以先flush给客户端head前面的html内容&#xff0c;让浏览器尽早的去请求)
2 后端处理渲染的数据&#xff0c;上方较快&#xff0c;下方较慢的情况(可以先行渲染上方较快的部分)

3.2 使用bigpipe的场景

对于更为复杂一点的bigpipe方式&#xff0c;如果上面的情况就适用于你的网站了的话&#xff0c;则最好采用简单的分块传输&#xff0c;否则如下情况&#xff0c;需要回填&#xff0c;则采用bigpipe方式渲染页面。毕竟&#xff0c;使用js回填还是有性能损耗的。
1 后端有较慢的数据处理&#xff0c;阻塞住了页面的情况下&#xff0c;且最慢的部分不是在网页的最后。(可以把最慢的部分变为回填)
2 后端有多块儿数据要并行处理的情况下(你也不知道哪块儿先回来了&#xff0c;所以先渲染一个架子。对于并行的请求&#xff0c;先回来的先flush回填)

3.3 国内的应用

据笔者观察&#xff0c;新浪微博正是采用了bigpipe的方式进行渲染&#xff0c;如图3.3.1&#xff0c;我们看到新浪微博的左侧导航栏与中间feed流区块儿都是架空的&#xff1a;
clipboard.png
图3.3.1
在下方&#xff0c;有对左侧导航栏和中间feed流部分的回填&#xff0c;如图3.3.2
clipboard.png
图3.3.2

所以&#xff0c;整个网页的渲染效果如下(如图3.3.3/图3.3.4/图3.3.5)
clipboard.png
图3.3.3
clipboard.png
图3.3.4
clipboard.png
图3.3.5
笔者猜测&#xff0c;可能微博是并行渲染这几块儿的数据&#xff0c;所以采用了bigpipe的方式。

4 课后作业

请读者们回想一下&#xff0c;自己的网站到底适不适合使用分块儿传输&#xff0c;能否使用上面的技术&#xff0c;使自己的网站更快一些呢&#xff1f;如果使用的话&#xff0c;是适合使用普通的chuned提速呢&#xff1f;还是使用bigpipe进行提速呢&#xff1f;

如有说明不周的地方欢迎回复详询

本文中所有的例子&#xff0c;均在我的github上可以找到&#xff1a;
https://github.com/houyu01/ch...

接下来的一篇文章&#xff0c;我将会和读者们一起聊聊HTTPS那些事儿&#xff0c;不要走开&#xff0c;请关注我.....

https://segmentfault.com/a/11...

如果喜欢本文请点击下方的推荐哦&#xff0c;你的推荐会变为我继续更文的动力。

以上内容仅代表笔者个人观点&#xff0c;如有意见笔者愿意学习参考各读者的建议。



推荐阅读
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 1.man(相当于cmd--help)对不熟悉的命令想查询详细使用方法的帮助解释可以使用eg:manls就可以查看ls相关的用法注: ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHPMailer邮件类邮件发送功能的使用教学及注意事项
    本文介绍了使用国外开源码PHPMailer邮件类实现邮件发送功能的简单教学,同时提供了一些注意事项。文章涵盖了字符集设置、发送HTML格式邮件、群发邮件以及避免类的重定义等方面的内容。此外,还提供了一些与PHP相关的资源和服务,如传奇手游游戏源码下载、vscode字体调整、数据恢复、Ubuntu实验环境搭建、北京爬虫市场、进阶PHP和SEO人员需注意的内容。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • 在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的步骤和方法
    本文介绍了在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的详细步骤和方法。首先需要下载最新的Java SE Development Kit 9发行版,然后按照给出的Shell命令行方式进行安装。详细的步骤和方法请参考正文内容。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • 开发中,EXT封装的.NET控件,使用了ExtJsExtenderControl的开源控件,发现个问题,就是每次控件加载,都需要调EXT_ALL.JS文件,600K,导致页面加载很慢。想对这个问题进行 ... [详细]
  • 传送门上一篇:Day4-前端高频面试题之浏览器相关1、请介绍一下HTTP和HTTPS的区别?HTTPS是在HTTP的基础上加入了SSL协议 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 本文讨论了在PHP中将空格转换为问号的问题,并提供了解决方案。文章指出,空格不是标准的空格,而是特殊的0xC2 0xA0字符。作者尝试使用mb_convert_encoding函数将utf8字符串转换为gbk编码,但未成功。文章建议检查编辑器是否对空格进行了特殊处理,并提供了使用base64_encode函数打印结果的方法。最后,给出了完整的代码示例。 ... [详细]
  • 延迟注入工具(python)的SQL脚本
    本文介绍了一个延迟注入工具(python)的SQL脚本,包括使用urllib2、time、socket、threading、requests等模块实现延迟注入的方法。该工具可以通过构造特定的URL来进行注入测试,并通过延迟时间来判断注入是否成功。 ... [详细]
author-avatar
1212
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有