存档

‘CMS开源系统’ 分类的存档

您的浏览器不能播放当前视频,请点击此处安装Flash播放器 解决方法 精

2017年2月4日 评论已被关闭

您的浏览器不能播放当前视频,请点击此处安装Flash播放器 解决方法 精

说真的安装EduSoho程序真心不是那么容易呀。

 

服务器环境搭配好之后终于可以正常安装了,结果又出现了视频不能播放的问题,总是在上方提示:

 

您的浏览器不能播放当前视频,请点击此处安装Flash播放器

 

在官方客服kent的知道下终于解决了这个问题。

 

原因在于 服务器 php 未安装 fileinfo组件。

 

由于我是使用lnmp 一键安装包 搭建的环境 解决方法如下:

 

编译并安装fileinfo插件

 

cd /root/lnmp1.0-full/php-5.3.17/ext/fileinfo

/usr/local/php/bin/phpize

./configure –with-php-config=/usr/local/php/bin/php-config

make && make install

在PHP配置中添加fileinfo插件

 

用vim编辑器编辑/usr/local/php/etc/php.ini文件

找到 “;extension=php_bz2.dll” 这一行

在其上面添加一行:

extension = fileinfo.so

然后重启lnmp

/root/lnmp restart

 

Discuz uc.key泄露导致代码注入漏洞修复

2016年12月13日 评论已被关闭

Discuz uc.key泄露导致代码注入漏洞修复
http://blog.sina.com.cn/s/blog_3eba8f1c0102xhf3.html

漏洞名称:Discuz uc.key泄露导致代码注入漏洞
文件路径:bbs/api/uc.php

修复方式:
1. 查找 updatebadwords 函数:
function updatebadwords($get, $post){
// …
// 添加: 约241行
// Discuz uc.key泄露导致代码注入漏洞
if(substr($v[‘findpattern’], 0, 1) != ‘/’ || substr($v[‘findpattern’], -3) != ‘/is’) {
$v[‘findpattern’] = ‘/’ . preg_quote($v[‘findpattern’], ‘/’) . ‘/is’;
}
// — end : 2016-08-22 —

$data[‘findpattern’][$k] = $v[‘findpattern’];
// …
}

2. 查找 updateapps 函数:
function updateapps($get, $post) {
// …
// 修改: 约280行
$UC_API = ”;
if($post[‘UC_API’]) {
// $UC_API = $post[‘UC_API’]; // 注释
$UC_API = str_replace(array(‘\”, ‘”‘, ‘\\’, “\0”, “\n”, “\r”), ”, $post[‘UC_API’]);
unset($post[‘UC_API’]);
}
// …
}

分类: CMS开源系统 标签:

阿里提示Discuz uc.key泄露导致代码注入漏洞的解决方法

2016年12月13日 评论已被关闭

阿里提示Discuz uc.key泄露导致代码注入漏洞的解决方法

http://www.moke8.com/article-15381-1.html

 

漏洞名称:Discuz uc.key泄露导致代码注入漏洞
补丁编号:6890270
补丁文件:/data/wwwroot/www.baidu.com/api/uc.php
补丁来源:云盾自研
更新时间:2016-12-13 09:16:41
漏洞描述:在Discuz中,uc_key是UC客户端与服务端通信的通信密钥,discuz中的/api/uc.php存在代码写入漏洞,导致黑客可写入恶意代码获取uckey,最终进入网站后台,造成数据泄漏。您也可以登录官方网站更新到最新版本解决。【注意:该补丁为云盾自研代码修复方案,云盾会根据您当前代码是否符合云盾自研的修复模式进行检测,如果您自行采取了底层/框架统一修复、或者使用了其他的修复方案,可能会导致您虽然已经修复了改漏洞,云盾依然报告存在漏洞,遇到该情况可选择忽略该漏洞提示】
这几天看到很多人问discuz uc.key 泄露导致代码注入漏洞uc.php的解决方法,也看了最近大家提供的一些解决方案,对比文件后发现最新版本的uc.php已经修复了大家说的问题,但阿里云一样有相关的提示,下面提供下相关的修改说明,大家可以试试看

首先找到这个文件/api/uc.php

第一处修改
if(!API_UPDATEBADWORDS) {
return API_RETURN_FORBIDDEN;
}
$data = array();
if(is_array($post)) {
foreach($post as $k => $v) {
//dz uc-key修改开始
if(substr($v[‘findpattern’], 0, 1) != ‘/’ || substr($v[‘findpattern’], -3) != ‘/is’) {
$v[‘findpattern’] = ‘/’ . preg_quote($v[‘findpattern’], ‘/’) . ‘/is’;
}
//end 修改结束
$data[‘findpattern’][$k] = $v[‘findpattern’];
$data[‘replace’][$k] = $v[‘replacement’];
}
}

第二处修改
function updateapps($get, $post) {
global $_G;
if(!API_UPDATEAPPS) {
return API_RETURN_FORBIDDEN;
}

//$UC_API = $post[‘UC_API’];
//dz uc-key修改开始
$UC_API = ”;
if($post[‘UC_API’]) {
$UC_API = str_replace(array(‘\”, ‘”‘, ‘\\’, “\0”, “\n”, “\r”), ”, $post[‘UC_API’]);
unset($post[‘UC_API’]);
}
//end修改结束
$cachefile = DISCUZ_ROOT.’./uc_client/data/cache/apps.php’;

第三处修改
$configfile = preg_replace
代替为
$configfile = preg_replace(“/define\(‘UC_API’,\s*’.*?’\);/i”, “define(‘UC_API’, ‘”.addslashes($UC_API).”‘);”, $configfile);

最新版本的UC里面都做了以上的修复的,如果你的是最新版本的X3.2就不需要更新,直接忽略阿里云的提示即可。

分类: CMS开源系统 标签:

阿里提示Discuz uc.key泄露导致代码注入漏洞uc.php的解决方法

2016年12月13日 评论已被关闭

阿里提示Discuz uc.key泄露导致代码注入漏洞uc.php的解决方法

http://ju.outofmemory.cn/entry/276023

本Discuz uc.key泄露导致代码注入漏洞适用所有用UC整合和程序,修复此漏洞所在的目录请在阿里云报告的位置进行查找,因为每个程序放置uc.php的目录不一定都是一样的。

漏洞名称:Discuz uc.key泄露导致代码注入漏洞

补丁文件:/api/uc.php

补丁来源:云盾自研

漏洞描述:在Discuz中,uc_key是UC客户端与服务端通信的通信密钥,discuz中的/api/uc.php存在代码写入漏洞,导致黑客可写入恶意代码获取uckey,最终进入网站后台,造成数据泄漏。您也可以登录官方网站更新到最新版本解决

解决方法:
首先找到这个文件/api/uc.php​
修复处有1处。
搜索如下代码(215行):

$configfile = preg_replace

将215行直接替换为如下代码:

$configfile = preg_replace(“/define\(‘UC_API’,\s*’.*?’\);/i”, “define(‘UC_API’, ‘”.addslashes($UC_API).”‘);”, $configfile);

修改后如下图:

修改完后保存上传更新,然后在阿里云点击修复即可。

以上就是俞视天下为各位提供的,阿里云提示:“Discuz uc.key泄露导致代码注入漏洞”的解决方案!

如果您未进行二次开发可以下载懒人包,请您下载当前服务器中的文件下来,进行备份后在进行修改上传复制操作!

分类: CMS开源系统 标签:

WordPress 博客合并文章分类目录的方法

2016年10月28日 评论已被关闭

WordPress 博客合并文章分类目录的方法

用 WordPress 做的一个传说中的垃圾站,由于内容比较杂,所以分类也就多得不可原谅,于是打算整理下,删除几个分类目录,但是担心连里面的文章也删除了,WordPress 也没有合并分类目录的方法,但是可以通过设置默认目录的方法来合并分类目录,下面博客吧来介绍下如何合并wordpress的分类目录。

合并WP分类目录的方法:

经过测试,删除 WordPress 分类目录,目录里面的文章是不会连同一起删除的,文章会自动归到博客的默认分类,所以合并的方法就是通过设置WP默认分类目录达到目的。

登陆WP博客后台,点击“设置”选项卡下的“撰写”选项进入“撰写选项”界面
在“默认文章分类目录”的下拉菜单中选择要合并的目录,即文章要移到的分类目录
保存更改后,到分类目录中删除不需要的分类目录,该目录下的文章就会自动转移到设置好的默认分类目录中
PS:这个方法省去了一篇一篇地修改分类目录的时间,省时省力。

分类: CMS开源系统 标签:

ECshop 在迁移到 PHP7 时遇到的兼容性问题

2016年10月26日 评论已被关闭

ECshop 在迁移到 PHP7 时遇到的兼容性问题

http://mt.sohu.com/20160129/n436340993.shtml

在 PHP7 上安装 ECShop V2.7.3时,报错!

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; ECS has a deprecated constructor in /usr/local/nginx/html/ecshop/upload/includes/cls_ecshop.php on line 25

这个报错的原因是 PHP7 不再支持与类名相同的构造方法,构造方法统一使用 __construct(), 比如下面的写法 PHP7 就会报这个错误。

<?php class foo { function foo() { echo ‘I am the constructor’; } } ?>

回到 ecshop 我们看一下 cls_ecshop.php 文件的25行。如下

果然有与类名相同的构造方法,我们将构造方法 ECS 修改为 __construct,

回到 ecshop 的安装首页刷新,发现已经没有错误了。

单击下一步,报错

Deprecated: Non-static method cls_image::gd_version() should not be called statically in /usr/local/nginx/html/ecshop/upload/install/includes/lib_installer.php on line 31

这个报错的原因是静态调用非静态方法,比如下面的代码就会报这个错误

<?php class foo { function bar() { echo ‘I am not static!’; } } foo::bar(); ?>

修改方法也很简单,要么将该方法改为静态方法,要么将该调用改为非静态调用。 我们看一下报错的文件 lib_installer.php 的 31行代码

还有clsimage类文件的 gdversion() 方法,可以看到的确没有使用 static关键字

第一种修改方式,将该方法修改为静态方法,在方法前加关键字 public static

第二种修改方式,采用非静态方式的调用,修改lib_installer.php 的 31行代码

这两种方法都可以解决问题。 回到ecshop的安装步骤第二页,错误提示已经不见了。

再下一步悲剧了,PHP7 不支持原始的 mysql api 了,PHP7 支持更好的 Mysqli API 和 pdo_mysql api 所以 ecshop 不改掉操作 mysql 的 api 是无法在 PHP7 上运行起来了。

分类: CMS开源系统 标签: ,

解决方案:安装wordpress出现500 Internal Server Error

2016年10月23日 评论已被关闭

解决方案:安装wordpress出现500 Internal Server Error
https://www.aliyun.com/zixun/content/3_12_194015.html

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html”>SEO诊断 淘宝客 云主机 技术大厅

黄坤我在做一个资讯站点的时候遇到一个wordpress不知道算不算常见的问题:程序安装的时候提示500 Internal Server Error

那么最终百度谷歌找到以下解决方案:

安装新版本wordpress出现500 Internal Server Error的问题:

在./wp-includes/class-http.php的291行,改成

$request_order = apply_filters( ‘http_api_transports’, array( ‘streams’ ), $args, $url );

也就是去掉这几个字符。

‘curl’,

如图:

注意:

部分wordpess程序可能不是291行,那请搜索

$request_order = apply_filters( ‘http_api_transports’, array( ‘curl’, ‘streams’ ), $args, $url );

然后将这一句代码替换为

$request_order = apply_filters( ‘http_api_transports’, array( ‘streams’ ), $args, $url );

 

然后覆盖到wp-includes文件夹下,覆盖前,为了防止出错,请备份下原文件。

原文地址:http://www.jmdrkj.cn/251.html

分类: CMS开源系统 标签:

WordPress迁移到Nginx上遇500错误

2016年10月23日 评论已被关闭

WordPress迁移到Nginx上遇500错误
http://www.annhe.net/article-2410.html
今天将wordpress从apache上迁移到了nginx,数据库配置无误后仍然打不开,检查http状态,结果返回500:

http 500 error

http 500 error
之前在apache下.htaccess配置错误的时候会遇到类似的错误,于是首先想到nginx的伪静态配置有问题,nginx下wordpress用的伪静态规则如下:
location / {
if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}

location / {
if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}
禁用伪静态之后仍然打不开,全新安装一个wordpress,使用上面的伪静态规则,可以正常访问,证明伪静态规则无误。

然后突然发现php文件不可执行,怀疑是这个原因造成的,于是将所有php文件加上了可执行属性,仍然不行,看刚才那个全新安装的wordpress,php没有可执行属性一样运行的好好的,看来不是这个原因。虽然这个方法没有解决问题,但也是有收获的,用 chmod 755 -R *.php 并不能按照预想的那样把当前目录及子目录全部php文件加上可执行属性,正确的方法应该是:
find path -type f -exec chmod 755 {} \;
1
find path -type f -exec chmod 755 {} \;
解释一下 {}是将find的结果一个个的传递给chmod作为参数,分号”;”是-exec的必须参数,告诉exec命令结束了,但 “;” 也是shell命令结束的关键字,所以要转义或者引用,即也可以写作:
find path -type f -exec chmod 755 {} “;”
1
find path -type f -exec chmod 755 {} “;”
最后还是得靠度娘,找到一篇文章(链接:http://www.douban.com/note/242967533/),提到缓存插件会有影响,才想起自己安装了object-cache缓存插件,将object-cache.php移走,果然可以正常访问了,可是,没有说在nginx下面就不能用object-cache呀,是不是得重启memcached呀?于是 /etc/init.d/mem….tab …tab….怎么就不能自动补全呢?!

 

原来是还没装memcached !!!!

害我折腾这么久–_–。

装完memcached,终于可以访问了。继续迁移其他站…EOF

分类: CMS开源系统 标签:

21运维网站模板D8主题以及WordPress插件使用情况

2016年5月29日 评论已被关闭

21运维网站模板D8主题以及WordPress插件使用情况

http://www.21yunwei.com/archives/3514

今天遇到一个访客留言咨询了一点该站主题以及插件情况,这里做一个针对本站简单的阐述,希望对以后使用wp程序以及插件的朋友有所帮助。
本站21运维使用程序:WordPress 4.5
使用主题: 大前端D8
插件使用情况:
Akismet插件:
防止垃圾评论。
Baidu Sitemap Generator插件 : 生成百度 Sitemap XML 文件。就相当于网站被百度订阅,进而为您的网站带来潜在的流量。同时生成一个静态的站点地图页面,对所有的搜索引擎都有利。
DX-auto-save-images插件 :  自动保持远程图片到本地,并且自动生成缩略图。
Link Manager插件 : 创建友情链接以及其他链接。
myQaptcha插件 :在单页文章评论处添加滑动解锁,使用Session技术防止垃圾评论和机器人,让你不用整天忙于文章审核.纯绿色插件,不修改数据库、无需中转页面、无需加载任何第三方代码。
WP Code Highlight插件 :代码高亮插件。用以带有代码的显示,显示模式可以自己设置。
WP-Mail-SMTP插件 :给自己的网站设置邮箱,采用smtp发送。不是自己独立的服务器一般不支持mail函数,设置smtp比较方便。
ZgBoke Nav插件 :中国博客联盟-成员展示导航Wordpress插件。也可以自己修改代码。

wordpress的插件非常的多,功能也比较强大,需要的朋友可以按照自己想法来设置。wordpress插件尽量还是比较少的安装,如果安装过多,会影响网站加载速度。

分类: CMS开源系统 标签:

WordPress 博客合并文章分类目录的方法

2016年5月13日 评论已被关闭

WordPress 博客合并文章分类目录的方法
http://www.boke8.net/wordpress-merger-catalog.html
用 WordPress 做的一个传说中的垃圾站,由于内容比较杂,所以分类也就多得不可原谅,于是打算整理下,删除几个分类目录,但是担心连里面的文章也删除了,WordPress 也没有合并分类目录的方法,但是可以通过设置默认目录的方法来合并分类目录,下面博客吧来介绍下如何合并wordpress的分类目录。

合并WP分类目录的方法:

经过测试,删除 WordPress 分类目录,目录里面的文章是不会连同一起删除的,文章会自动归到博客的默认分类,所以合并的方法就是通过设置WP默认分类目录达到目的。

登陆WP博客后台,点击“设置”选项卡下的“撰写”选项进入“撰写选项”界面
在“默认文章分类目录”的下拉菜单中选择要合并的目录,即文章要移到的分类目录
保存更改后,到分类目录中删除不需要的分类目录,该目录下的文章就会自动转移到设置好的默认分类目录中
PS:这个方法省去了一篇一篇地修改分类目录的时间,省时省力。

分类: CMS开源系统 标签:

TTFB-首字节时间简介

2016年5月12日 评论已被关闭

TTFB-首字节时间简介

http://www.cnblogs.com/ChandlerVer5/p/TTFB.html

百度站长工具里看到有一个“首字节时间”的建议,第一次听说,还真不知道是什么东东。百度站长工具里面的解释是:“浏览器开始收到服务器响应数据的时间=后台处理时间+重定向时间,是反映服务端响应速度的重要指标”。

看到这个解释,隐隐约约明白了什么意思,下面就用自己的话说一下我的理解(如果有人有权威解释,发现本解释错误,还望指正)。

“首字节时间”顾名思义就是在浏览器输入目标网站的网址并回车后(或者搜索页面点击打开新的目标页面时)直到获得首个字节的时间。再解释一下,后台处理时间(这应该是浏览器访问目标网站网址时,发出请求,域名服务器的处理时间,将请求发送到目标网站所在服务器ip),重定向时间(这应该是域名服务器将请求发送到目标网站服务器后,如果服务器有重定向设置,就处理重定向的时间)。

“首字节时间”简单的理解就是,访问目标网站时,从发出请求到自己电脑获得网站响应的首字节这段时间。

总而言之,言而总之,首字节时间当然是越短了越好。就像百度自己的解释,这是反映服务端响应速度的重要指标。首字节时间越短,表明服务器端(域名DNS服务器和网站服务器)响应速度越快,反之越长,表明服务器端响应速度慢。当然是越快了对网站访问体验来说越好了!

=============================================================================================================================================

TTFB-首字节时间,是指从客户端开始和服务端交互到服务端开始向客户端浏览器传输数据的时间(包括DNS、socket连接和请求响应时间),是能够反映服务端响应速度的重要指标,获取在接收到响应的首字节前花费的毫秒数。
lTime = Response.TTFB
返回值 lTime As Long:首字节响应时间(以毫秒为单位)。

TTFB:httpwatch的timechart中的一列参数。

课外学习部分:

什么是TTFB呢?
1.TTFB (Time To First Byte),是最初的网络请求被发起到从服务器接收到第一个字节这段时间,它包含了 TCP连接时间,发送HTTP请求时间和获得响应消息第一个字节的时间。
注意:网页重定向越多,TTFB越高,所以要减少重定向
TTFB优化的方法有:

1.减少DNS查询

2.使用CDN

3.提早Flush

4.添加周期头


什么是TTSR呢?
2.TTSR(Time to Start Render)
TTSR-开始渲染时间,指某些非空元素开始在浏览器显示时的时间,这也是一项重要指标,即TTSR越短,用户越早浏览器中的内容,心理上的等待时间会越短。过多的CPU消耗会拖慢TTSR,所以网站中有大量图片和脚本往往会造成不良用户体验。

注意
TTSR优化:
1.优化TTFB
2.降低客户端CPU消耗,即页面加载初期不要有大脚本运行,把JS脚本放到页面下方
3.使用效率较高的CSS选择器,避免使用CSS表达式
4.避免使用CSS滤镜

前端TTSR测试脚本:

复制代码
<head> 
        <script> 
            (function(){ 
                var timeStart = + new Date, 
                    limit = 1, 
                    timer = setInterval(function(){ 
                    if((document.body&&document.body.scrollHeight > 0) || (limit++ == 500)){ 
                        clearInterval(timer); 
                        console.info('TTSR:',+ new Date - timeStart,';duration:',limit); 
                    } 
                },10); 
            })() 
        </script> 
    </head>
复制代码

在页面端无法简单测试出具体的TTSR,不过可以通过模拟脚本得到大概的时间,Firefox提供了一个MozAfterPaint事件,经测试,用于TTSR并不准确,如果有MozBeforePaint事件该有多好。

什么是TTDC呢?
3.TTDC(Time to Document Complete)
TTDC-文档完成时间,指页面结束加载,可供用户进行操作的时间,等价于浏览器的onload事件触发点。TTDC是比较重要的性能优化对象,TTDC越低,页面加载速度越快,用户等待时间越短。
注意
TTDC的优化方法有:

1.优化TTFB

2.优化TTSR

3.优化首屏时间,将不必要的页面加载放到onload事件之后

TTDC前端测试:
常见性能测试平台大多使用IE浏览器的DocumentComplete事件来度量TTDC,DocumentComplete事件触发时,页面的状态应是READYSTATE_COMPLETE,所以在页面中我们可以用JS脚本判断:

复制代码
var win = window,doc = document; 
if(win.attachEvent || doc.hasOwnProperty('onreadystatechange')){ 
doc.onreadystatechange = function(){ 
 if(doc.readyState == 'complete'){ 
  /** 
  * test 
    do something... 
   */ 
  } 
} 
}else{ 
  win.addEventListener('load',function(){ 
 /** 
  * test 
   do something... 
  */ 
 },false); 
}
复制代码

 

什么是TTFL呢?
4.TTFL(Time to Fully Loaded)
TTFL-完全加载时间,指页面在onload之前和onload事件之后额外加载的内容所花费的时间的总和,即页面完完全全加载完毕消耗的总时间。
注意
TTFL的优化方法:

1.优化TTFB

2.优化TTSR

3.优化TTDC

4.延迟加载

5.异步加载

6.按需加载

=======================================================================================================================================================

如何优化网页首字节时间
1:
看一下详情分析页面。
DNS解析:如果是 DNS 解析时间太长,那是你的域名解析服务器不好,请更换靠谱的 NS 服务器。
初始化连接:如果是初始化连接的时间太长,那是你机房的网络不好,请更换更好的机房
如果上面两个都不是。那就是你的代码性能不好,代码执行消耗的时间太长。请优化代码,或者更换更好的机器。
2:
客户端t1时刻发起对于某个url的请求,经过DNS解析获取相应的IP地址后,发起对该IP地址的socket连接,在完成三次握手建立tcp连接后,客户端发送http请求信息,服务端收到请求后返回响应的内容,当客户端在t2时刻收到服务端返回内容的第一个字节,则第一字节时间=t2-t1。 第一字节的时间= DNS解析的时间+socket三次握手时间+http请求时间+第一字节返回的时间。 首字节的时间是0,说明很快呀。不需要做优化。 谢谢使用阿里测!

 

<摘自:http://www.liu16.com/post/390.html&http://www.wenshuai.cn/home/article/detail/id/53.html&http://segmentfault.com/q/1010000000259751>

分类: CMS开源系统 标签:

这次真切的感受到了 WordPress 静态缓存的重要性

2016年5月12日 评论已被关闭

这次真切的感受到了 WordPress 静态缓存的重要性

https://cnzhx.net/blog/felt-the-importance-of-static-cache-for-wordpress/

今天碰巧发现 VPS 的 CPU 占用率达到60%,就检查了一下服务器,发现是因为国内一个 IP 在扫描网站上可能存在的压缩文件包(估计是那种寻找机会的无聊“黑客”)。顺便测试网站在国内的连通性的时候发现之前响应速度超快的网站居然变得很慢。

慢到什么程度?一次测试中,Time to First Byte (TTFB,首字节时间,也就是从客户端开始和服务端交互到开始接收到服务端发送网页数据的时间)居然达到了将近 3 秒。之前的测试中还真没有遇到过超过 1.5 秒的情况。

为此检查了半天,最后还把服务器重起了一次。真心以为是最近安装的论坛影响了响应速度。可是又开始怀疑,毕竟一个刚刚安装的测试论坛怎么也不会有这么大的消耗。

误打误撞的打开了 WP Super Cache 的配置页面才忽然发现不知道什么时候把它给关闭了。赶紧重新启用 WPSC,然后再去测试,兴奋的发现 TTFB 只有 54ms。

所以看来随着 WP 越来越臃肿,网站内容和访问数越来越多,网页静态化缓存就显得越来越重要。这次算是真切的感受了一把。记下来给自己,也给网友们提个醒。©

分类: CMS开源系统 标签:

不用担心TTFB时间过长

2016年5月12日 评论已被关闭

不用担心TTFB时间过长

http://cuixu.cn/stop-worrying-ttfb/

时间第一个字节是经常被用来作为如何快速的Web服务器响应请求和常见的Web服务测试报告它的措施。的速度就越快越好Web服务器(在理论上)。但理论是不是很好。
维基至第一字节定义时间为“从虚拟用户作出HTTP请求到页面的第一个字节被接收到浏览器中的持续时间”。但是,什么流行的网页测试网站居然报到?要找出我们创建了一个测试服务器中插入延迟到HTTP响应,找出什么是真正被测量。答案是一个巨大的惊喜和发现TTFB不是一个有用的指标。
当Web浏览器请求一个页面从Web服务器发送请求本身和一些头指定的东西,如可接受的格式的响应。服务器与状态行响应(这通常是HTTP / 1.1 200 OK指示该页面是可用的),然后加入更多的头(含约页面信息),最后页的内容。
CloudFlare的TTFB测试服务器不同的行为一点。当它接收到一个请求发送的HTTP / 1.1 200 OK(轰)的第一个字母,然后发送标题和页面本身的其他部分之前等待10秒。 (你可以抓住这里的TTFB服务器的代码;它写在Go)。
如果你问WebPageTest从CloudFlare的TTFB服务器下载页面,你获得以下惊喜。 WebPageTest报时间至第一字节为轰收到(而不是时间的页面本身实际发送)的时间。 10秒的等待使得这种显而易见的。

相同数量的报告被戈麦斯。
该TTFB所报告不是页的第一数据字节,但是HTTP响应的第一个字节的时间。这些都是由于响应头可以非常迅速地产生非常不同的东西,但它是将影响所有的最重要的指标数据:如何快速用户得到看到该页面。
在CloudFlare的我们广泛使用nginx的,并在调查TTFB跨显著差异从nginx的进来TTFB时,压缩或不使用。网页gzip压缩大大缩短了网页下载时间,但压缩本身是有成本的。这会导致成本要TTFB更大,即使完整的下载更快。
为了说明,我们采取了最大的维基百科页面(高级龙与地下城第二版怪兽的列表),并使用nginx的有和没有启用gzip压缩服之。下表显示了TTFB和总下载时间与压缩和关闭。

| TTFB | Page loaded ————————— | ——- | ————- No compression (gzip off) | 213us | 43ms Compressed (gzip on) | 1.7ms | 8ms

请注意如何与gzip压缩,网页被下载5倍的速度更快,但TTFB是8倍大。这是因为nginx的等待,直到压缩发送HTTP头之前已经开始;当压缩关闭它发出的头直掉。所以,如果你看一下TTFB看上去好像压缩是一个坏主意。但你看看下载的时候,你看到对面。 从最终用户的角度来看TTFB几乎是无用的。在这个(实)例如它的实际负的下载时间相关:越差TTFB更好的下载时间。窥视到nginx的源代码,我们意识到,我们可以欺骗和快速发送标题,这样它看起来像我们TTFB是太棒了,即使压缩,但最终我们决定不:这也将有负面的最终用户体验的影响,因为我们将有当浪费TCP正在经历缓慢的开始了宝贵的数据包的权利。它会作出的CloudFlare好看一些测试,但实际上伤害了最终用户。 也许是作为一种趋势的唯一一次TTFB是非常有用的。而且它最擅长的服务器本身,使网络延迟消除测量。通过检查一个趋势有可能发现是否有Web服务器(如它超载)上出了问题。 测量TTFB远程意味着你还测量在相同的时间,这掩盖了事情TTFB实际测量网络延迟:Web服务器的速度有多快能够响应请求。 在的CloudFlare TTFB不是显著度量。我们感兴趣的优化终端用户体验,这意味着真正的最终用户页面是可见的时间。我们将推出专门的工具来监控最终用户体验,使我们所有的出版商能看到并测量他们的访客正在经历。

分类: CMS开源系统 标签:

关于请求被挂起页面加载缓慢问题的追查

2016年5月12日 评论已被关闭

关于请求被挂起页面加载缓慢问题的追查

http://fex.baidu.com/blog/2015/01/chrome-stalled-problem-resolving-process/

本文前戏较多,务实的同学可以直接跳到文末的结论。

由「钢的琴」网友脑洞大开延伸出了吉的他二的胡琵的琶,以及后来许嵩的「苏格拉没有底」,是否可以再拓展一下,得到哥本不爱吃哈根,哈根爱达斯等剧情乱入的关系。

上面跟本文要讨论的主题有什么关系?

没关系。

缘起

有用户反馈内部MIS系统慢,页面加载耗时长。前端同学们开组会提及此事,如何解决慢的问题。

最致命的是:偶发!你不能准确知道它抽风的时间点,无法在想要追查问题的时候必现它。 这只是一方面,另外,慢的可能实在太多了,那么问题来了,是前端导致的还是后端的问题?

对慢的定义也有待商榷,多久算慢?如果这个页面加载大量数据耗时增加那我认为这是正常的。但这个时限超过了一个合理的自然值,就变得不那么正常了,比如四五十秒,一分多钟。

最奇葩的是,如此久的耗时居然不会报超时错误,而是拿到正确返回后将页面呈现了出来!

可能的原因

初步猜测

初步的猜测可能是后端迟迟未返回造成浏览器处于等待状态。这个猜测是很合乎逻辑的,至少能够很合理地解释Chrome Dev Tool 网络面板中我们看到的状态pending

但我们不能停留在猜测阶段,要用事实说话,数据才不会骗人。这也正是本文将要展开的。

下面是另外一些被提出来的可能性。

Angular

Angular首当其冲。为什么,因为这个问题出现在后台MIS系统中,且这些系统多用Angular开发。

Angular :怪我咯。

因为问题多出现在基于Angular的MIS系统中,并且Angular的性能一直是被诟病的,所以听到不少的声音将矛头指向Angular。这似乎没什么好庇护的。Angular在整个项目中的前端部分扮演了很重的角色。树大招风,理所当然。

这让我想起初次接触到这个问题时,那是在七月份,芙蓉的爱马仕平台用户反馈了慢的问题,报到前端,顺便看了下,一看Pending状态,觉得是后端未返回。只是情深缘浅当时也没有深入,同时洪堂大神负责去追查了。当时那个系统,很负责地说,没有用Angular。

所以这里可以为Angular正身,将其排除。

内部封装的commonResource

内部对Angular原生的resource进行了封装,做了些数据的转换处理。既然上面Angular都被正身了,那么这里的怀疑也是站不住脚的。

Chrome插件

经查,网上好多呼声有说是Adblock等与网络有关的Chrome插件。可我不使用它已经很多年,那玩意儿太重,后来找到了算法更高级体量更轻便的µBlock。关键是后者也在我使用一段时间后放弃了,因为个人觉悟提高了(此处逼格开始膨胀),免费内容是需要广告支撑的,如果你不希望付费变成强制的话。所以现在一直是处于未开这类插件的状态。那么在未开广告屏蔽插件的情况下重现了问题,可以排除这类插件的影响了。

关于插件,此刻我的Chrome里唯一还会接管Chrome网络的便是代理插件SwitchSharp, 升级之后这货叫Switchy哦卖喝(与时俱进的我当然使用的是后者,此处逼格已经爆表)。

Chrome独家?

因为内部MIS只兼容了Chrome开发,所以不会有在除了Chrome之外的浏览器上使用的场景,并且其他浏览器上面追查问题也是很痛苦的事情。这里仅在火狐里进行了少量尝试,未复现。同时接到反馈,Safari里也未复现。但也不能肯定就只有Chrome存在问题。似乎这个对于问题的解决还不那么重要,所以先不管。

杀毒软件

后面会看到,在追查错误号ERR_CONNECTION_RESET时引出了杀毒软件可能会导致Chrome工作不正常的情况,但这个可能也在稍后被排除人。

并且,我厂使用Mac的同学并没有安装杀软,依然是可以复现的。

重现

第一件事情便是重现。虽然是偶发,为了尽可能保存现场,还是想要手动将它刷出来。天不灭我,经过良久尝试,该问题被复现。于是各种截图,保存请求数据。这个时候还没有开启chrome://net-internals/#events页面来捕获事件日志。

为以后引用方便,这里留下版本信息:

OS: Windows 7 Ultimate

Chrome:Version 39.0.2171.95 m

这是请求Pending时的请求信息:

这是请求成功返回后:

可以看到Stalled了1分多钟。神奇的是竟然不报超时错误而是成功返回了。

同时保存了请求头,响应头,还将本次问题请求保存成了CURL等。现场已经留下,感觉Bug不会存活太久了。

接下来就是对比正常请求跟这次异常请求的不同,一轮比较下来,未发现多少异常。

常态与变态的对比

请求头对比:

请求头的对比已丢失,但除了时间外,其余无差别。

响应头对比:

返回结果对比:

上面的对比意义不大,但还是要做的,万一发现有价值的情报了呢。

一次失败的尝试

解决问题时,习惯性地看有没有人已经碰过到类似问题,这样做的好处很明显: 如果有,站在巨人的肩上轻松地牛逼着; 如果没有,这是个机会。

于是信心满满地出发了,因为根据一条互联网准则,70%的问题已经有人解决过了,那些没有被解决的要么是现有技术达不到,要么是未被人发现。所以能够搜索出问题答案的概率还是蛮大的。

经过旷日持久的搜索,有价值的参考寥寥无几。可能是问题本身太过奇葩,遇到的人太少;也有可能问题过于晦涩,无法表述;抑或我搜索的关键词不够精准。 倒也不是说一个都没找到,但一般涉及网络日志的情况就无人问津了,无人问津了!

比如这个,一年多前被人问的,现在还没有一个回答。

还比如这个 > Chrome stalls when making multiple requests to same resource?

是后来作为参考的,也是无人问津了……

甚至自己也去问了一个,依然无人问津问津……

神秘的CACHE LOCK

上面提到,Stackoverflow上找到一个问题,跟现在需要解决一有些类似点:

  • 偶发,并不是必然出现的。这里我们的问题也是偶发,很难复现,需要反复刷。
  • 也是请求被Pending了很久,从请求的时间线来看,体现在Stalled上。

这一刻,有一种感觉大概是这样的:

伟大的意大利的左后卫!他继承了意大利的光荣的传统。法切蒂、卡布里尼、马尔蒂尼在这一刻灵魂附体!格罗索一个人他代表了意大利足球悠久的历史和传统,在这一刻他不是一个人在战斗,他不是一个人!

突然看到了希望。该提问到没有给出什么建设性的意见,但它后面的追加编辑却给出了答案。过程是查看Chrome的网络日志,在事件里面发现有一个超时错误:

t=33627 [st= 5] HTTP_CACHE_ADD_TO_ENTRY [dt=20001] –> net_error = -409 (ERR_CACHE_LOCK_TIMEOUT)

耗时20秒之久!而且写得非常明显是ERR_CACHE_LOCK_TIMEOUT。根据提问者贴出来的链接,了解到Chrome有一个缓存锁的机制。

具体源于一个今年6月分实现的一个补丁,加入了这么个机制,而这个机制的引入又源于2010年的一个issue。具体信息可以通过这个这里查看,下面引用如下。

Basically here is the situation:

The site author has a long-lived XHR being used to stream a slow response from the server. This XHR response is cachable (it is just really slow). They kick off the XHR asynchronously, and as data slowly arrives on it, update the progressive load of the webpage. Cool.

Now what happens if you try to load this page in multiple tabs of Chrome is: The first page starts to load just fine, but the second one does nothing. What has happened, is the background XHR of the first page load has acquired an exclusive lock to the cache entry, and the background XHR of the second page is stalled at “Waiting for cache…” trying to get a reader access to the cache entry.

Since the first request can takes minutes, this is a problem.

eroman 同学指出了这么一个事实:

浏览器对一个资源发起请求前,会先检查本地缓存,此时这个请求对该资源对应的缓存的读写是独占的。那么问题来了,试想一下,当我新开一个标签尝试访问同一个资源的时候,这次请求也会去读取这个缓存,假设之前那次请求很慢,耗时很久,那么后来这次请求因为无法获取对该缓存的操作权限就一直处于等待状态。这样很不科学。于是有人建议优化一下。也就是上面所描述的那样。

随着问题的提出,还出了两种可能的实现方案。

(a) [Flexible but complicated] Allow cache readers WHILE writing is in progress. This way the first request could still have exclusive access to the cache entry, but the second request could be streamed the results as they get written to the cache entry. The end result is the second page load would mirror the progress of the first one.

(a) [Naive but simpler] Have a timeout on how long we will block readers waiting for a cache entry before giving up and bypassing the cache.

我猜上面第二个(a)应该是(b)。简单说第一种优化方案更加复杂但科学。之前的请求对缓存仍然是独占的,但随着前一次请求不断对缓存进行更新,可以把已经更新的部分拿给后面的请求读取,这样就不会完全阻塞后面的请求了。

第二种方案则更加简单暴力。给后来的请求设定一个读取缓存超时的时限,如果超过了这个时限,我认为缓存不可用或者本地没有缓存,忽略这一步直接发请求。

于是Chromium的开发者们选择了后者简单的实现。也就是Issue 345643003: Http cache: Implement a timeout for the cache lock 这个提交里的实现。

这个提交的描述如下:

The cache has a single writer / multiple reader lock to avoid downloading the same resource n times. However, it is possible to block many tabs on the same resource, for instance behind an auth dialog.

This CL implements a 20 seconds timeout so that the scenario described in the bug results in multiple authentication dialogs (one per blocked tab) so the user can know what to do. It will also help with other cases when the single writer blocks for a long time.

The timeout is somewhat arbitrary but it should allow medium size resources to be downloaded before starting another request for the same item. The general solution of detecting progress and allow readers to start before the writer finishes should be implemented on another CL.

于是就产生了上面题主遇到的情况。

所以他的解决方法就很明朗了,对请求加个时间戳让其变得唯一,或者服务器响应头设置为无缓存。Both will work!

那么我们的问题也会是这样的么?我幻想由于某种未知的原因造成之前的请求不正常(虽然网络面板里没有数据证明这样的阻塞请求在问题请求之前存在),然后我们的MIS里打开页面时读取不到缓存,卡了,一会儿缓存好了,正常了,于是在等待了几十秒后请求成功发出去了。

似乎不太可能。因为恰好内部MIS系统的响应头里已经加了缓存控制了 Cache-Control: no-cache

以下是一次问题请求的响应头:

HTTP/1.1 200 OK
Date: Wed, 31 Dec 2014 11:47:21 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Pragma: no-cache
Cache-Control: no-cache
tracecode: 28410188240979065866123119
tracecode: 28410188240506537994123119
Server: Apache

并且开多个标签也是无法进行有效重现的。

因此可以排除缓存的干扰。那么似乎这里的缓存锁并不是导致问题的原因,只能另寻他路。不得不说,高兴过后有点失望。

八卦时间

可喜的是,在细细口味了上面缓存机制引入的过程后,真是耐人寻味。这里不妨八卦一下。相信你也注意到了,上面提到,该缓存问题的提出是在2010年,确切地说是Jun 8, 2010。是的,2010年6月8日由eroman 同学提出。但最后针对该问题进行修复的代码提交却是在今年6月份,2014年6月24日,提交时间摆在那里我会乱说?

于是好奇为什么会拖了这么久,遂跟了一下该问题下面的回复看看发生了什么。简直惊呆了。

  • 同月14号,有了首次对这个问题的回复,那是将该问题指派给了rvargas同学。
  • 一个月过去了,也就是7月15号,rvargas同学指出了与该问题关联的另外一个issue「issue 6697
  • 接下来是8月5日,rvargas同学为该问题贴上了标签-Mstone-7 Mstone-8 ,表明将会在里程碑7或者8里面进行修复。但在后面的10月7日,这个日程又被推到了-Mstone-8 Mstone-9
  • 再接下来11月5日,有人表示以目前的速度及bug数量,还没有时间来修复它,重点在处理优先级为p1的问题上。于是此问题又成功被顺延了,来到-mstone-9 Mstone-10 ,同时优级降为p2。Chromium人手也不够啊,看来。
  • 时间来到12月9日,因为优先级为p2的issue如果没有被标为开始状态的话又自动推到下一个里程碑了,于是顺利来到 -Mstone-10 MovedFrom-10 Mstone-11 。次年2月来到-Mstone-11 Mstone-12 。完成了一次跨年!

…………

  • 上面省略N步。如此反复,最后一次被推到了-Mstone-16 ,那是在2011年10月12日。
  • 时间一晃来到2013年,这一年很平静,前面的几个月都没有人对此问题进行回复。直到11月27日,有人看不下去了,评论道:

This bug has been pushed to the next mstone forever…and is blocking more bugs (e.g https://code.google.com/p/chromium/issues/detail?id=31014)and use-cases same video in 2 tags on one page, and adaptive bit rate html5 video streaming whenever that will kick in. Any chance this will be prioritized?

由于这个bug的无限后延也阻塞了另外一些同类问题,看来是时候解决了。这不,最初的owner 当天就进行了回复:

ecently there was someone looking at giving it another try… I’d have to see if there was any progress there.

If not, I may try to fix it in Q1.

最后一句亮瞎。敢情这之前owner就没有想过要去真正解决似的,因为有其他人在看这个问题了,所以就没管了,如果Q1还没人解决的话,我会出手的!嗯,就是这个意思。

…………

最后,也就是上文提到的,2014年6月,还是rvargas同学对这个问题进行了修复,实现了对缓存读取20秒超时的控制。

该问题就是这样从2010来到2014的。我怀疑Chrome是如何成为版本帝的。

阶段总结

仅有的希望到此似乎都没有了。不过前面的努力也不是没有作何收获,至少我得到了以下有价值的信息:

  • 谷歌的神坛光环不再那么耀眼,他们的产品也是有大堆Bug需要处理的
  • Chrome 处理issue的效率,当然不排除这种大型项目bug数量跟人力完全不匹配的情况
  • 受上面Stackoverflow问题的启发,接下来我将重点转移到了针对出问题请求的日志分析上,并且取得了突破

开始新的征程

虽然上面的努力没能定位到问题,但作为这次对解决这次问题的尝试,还是将它记录了下来,估且称作「旧的回忆」吧。

下面开始「新的征程」。

再次重现

这次受到上面的启发,开启chrome://net-internals/#events页面来捕获事件日志。看是否有错误或异常发生。

再次经过旷日持久的机械操作,重现了!这次,日志在手,天下我有。感觉Bug不会存活多久了。

Chrome Dev Tools 网络面板截图:

由上面的截图看到,本次出问题的请求总耗时42.74秒。

问题请求的时间线信息截图:

可以预见,通过捕获的日志完全可以看到Stalled那么久都发生了些什么鬼。

话不多说,切换到事件捕获页面,定位到出问题的请求,查看其详情。同时将该日志导出,永久保存!作为纪念,也方便以后再次导入查看。有兴趣的同学可以访问下方下载后进行导入,就可以清晰地查看到现场了,就好像你亲历了整个犯罪现场一样。

日志还原

  • 下载该日志文件
  • 在Chrome新开一个标签输入chrome://net-internals/#events
  • 切换到Import,选择刚才下载的JSON文件进行导入
  • 切换到Events,定位到http://qa.tieba.baidu.com/release/getReleaseHistory?projectId=fum1.0.593 这个请求

此刻右边出现的便是该问题请求的详细日志。

日志解读

下面不妨把日志文件贴出来先:

193486: URL_REQUEST
http://qa.tieba.baidu.com/release/getReleaseHistory?projectId=fum1.0.593
Start Time: 2015-01-02 17:51:05.323

t=    1 [st=    0] +REQUEST_ALIVE  [dt=42741]
t=    1 [st=    0]    URL_REQUEST_DELEGATE  [dt=0]
t=    1 [st=    0]   +URL_REQUEST_START_JOB  [dt=42740]
                      --> load_flags = 339804160 (BYPASS_DATA_REDUCTION_PROXY | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)
                      --> method = "GET"
                      --> priority = "LOW"
                      --> url = "http://qa.tieba.baidu.com/release/getReleaseHistory?projectId=fum1.0.593"
t=    2 [st=    1]      URL_REQUEST_DELEGATE  [dt=0]
t=    2 [st=    1]      HTTP_CACHE_GET_BACKEND  [dt=0]
t=    2 [st=    1]      HTTP_CACHE_OPEN_ENTRY  [dt=0]
t=    2 [st=    1]      HTTP_CACHE_ADD_TO_ENTRY  [dt=0]
t=    2 [st=    1]      HTTP_CACHE_READ_INFO  [dt=0]
t=    2 [st=    1]      URL_REQUEST_DELEGATE  [dt=0]
t=    2 [st=    1]     +HTTP_STREAM_REQUEST  [dt=2]
t=    4 [st=    3]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                          --> source_dependency = 193488 (HTTP_STREAM_JOB)
t=    4 [st=    3]     -HTTP_STREAM_REQUEST
t=    4 [st=    3]     +HTTP_TRANSACTION_SEND_REQUEST  [dt=0]
t=    4 [st=    3]        HTTP_TRANSACTION_SEND_REQUEST_HEADERS
                          --> GET /release/getReleaseHistory?projectId=fum1.0.593 HTTP/1.1
                              Host: qa.tieba.baidu.com
                              Connection: keep-alive
                              Accept: application/json, text/plain, */*
                              User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
                              Referer: http://qa.tieba.baidu.com/project/
                              Accept-Encoding: gzip, deflate, sdch
                              Accept-Language: en-US,en;q=0.8
                              Cookie: [268 bytes were stripped]
t=    4 [st=    3]     -HTTP_TRANSACTION_SEND_REQUEST
t=    4 [st=    3]     +HTTP_TRANSACTION_READ_HEADERS  [dt=21301]
t=    4 [st=    3]        HTTP_STREAM_PARSER_READ_HEADERS  [dt=21301]
                          --> net_error = -101 (ERR_CONNECTION_RESET)
t=21305 [st=21304]        HTTP_TRANSACTION_RESTART_AFTER_ERROR
                          --> net_error = -101 (ERR_CONNECTION_RESET)
t=21305 [st=21304]     -HTTP_TRANSACTION_READ_HEADERS
t=21305 [st=21304]     +HTTP_STREAM_REQUEST  [dt=3]
t=21307 [st=21306]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                          --> source_dependency = 193494 (HTTP_STREAM_JOB)
t=21308 [st=21307]     -HTTP_STREAM_REQUEST
t=21308 [st=21307]     +HTTP_TRANSACTION_SEND_REQUEST  [dt=3]
t=21308 [st=21307]        HTTP_TRANSACTION_SEND_REQUEST_HEADERS
                          --> GET /release/getReleaseHistory?projectId=fum1.0.593 HTTP/1.1
                              Host: qa.tieba.baidu.com
                              Connection: keep-alive
                              Accept: application/json, text/plain, */*
                              User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
                              Referer: http://qa.tieba.baidu.com/project/
                              Accept-Encoding: gzip, deflate, sdch
                              Accept-Language: en-US,en;q=0.8
                              Cookie: [268 bytes were stripped]
t=21311 [st=21310]     -HTTP_TRANSACTION_SEND_REQUEST
t=21311 [st=21310]     +HTTP_TRANSACTION_READ_HEADERS  [dt=21304]
t=21311 [st=21310]        HTTP_STREAM_PARSER_READ_HEADERS  [dt=21304]
                          --> net_error = -101 (ERR_CONNECTION_RESET)
t=42615 [st=42614]        HTTP_TRANSACTION_RESTART_AFTER_ERROR
                          --> net_error = -101 (ERR_CONNECTION_RESET)
t=42615 [st=42614]     -HTTP_TRANSACTION_READ_HEADERS
t=42615 [st=42614]     +HTTP_STREAM_REQUEST  [dt=12]
t=42627 [st=42626]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                          --> source_dependency = 193498 (HTTP_STREAM_JOB)
t=42627 [st=42626]     -HTTP_STREAM_REQUEST
t=42627 [st=42626]     +HTTP_TRANSACTION_SEND_REQUEST  [dt=2]
t=42627 [st=42626]        HTTP_TRANSACTION_SEND_REQUEST_HEADERS
                          --> GET /release/getReleaseHistory?projectId=fum1.0.593 HTTP/1.1
                              Host: qa.tieba.baidu.com
                              Connection: keep-alive
                              Accept: application/json, text/plain, */*
                              User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
                              Referer: http://qa.tieba.baidu.com/project/
                              Accept-Encoding: gzip, deflate, sdch
                              Accept-Language: en-US,en;q=0.8
                              Cookie: [268 bytes were stripped]
t=42629 [st=42628]     -HTTP_TRANSACTION_SEND_REQUEST
t=42629 [st=42628]     +HTTP_TRANSACTION_READ_HEADERS  [dt=112]
t=42629 [st=42628]        HTTP_STREAM_PARSER_READ_HEADERS  [dt=112]
t=42741 [st=42740]        HTTP_TRANSACTION_READ_RESPONSE_HEADERS
                          --> HTTP/1.1 200 OK
                              Date: Fri, 02 Jan 2015 09:51:48 GMT
                              Content-Type: application/json; charset=UTF-8
                              Transfer-Encoding: chunked
                              Connection: keep-alive
                              Cache-Control: no-cache
                              tracecode: 31079600320335034634010217
                              tracecode: 31079600320537995786010217
                              Server: Apache
t=42741 [st=42740]     -HTTP_TRANSACTION_READ_HEADERS
t=42741 [st=42740]      HTTP_CACHE_WRITE_INFO  [dt=0]
t=42741 [st=42740]      HTTP_CACHE_WRITE_DATA  [dt=0]
t=42741 [st=42740]      HTTP_CACHE_WRITE_INFO  [dt=0]
t=42741 [st=42740]      URL_REQUEST_DELEGATE  [dt=0]
t=42741 [st=42740]   -URL_REQUEST_START_JOB
t=42741 [st=42740]    URL_REQUEST_DELEGATE  [dt=0]
t=42741 [st=42740]    HTTP_TRANSACTION_READ_BODY  [dt=0]
t=42741 [st=42740]    HTTP_CACHE_WRITE_DATA  [dt=0]
t=42741 [st=42740]    HTTP_TRANSACTION_READ_BODY  [dt=0]
t=42741 [st=42740]    HTTP_CACHE_WRITE_DATA  [dt=0]
t=42742 [st=42741] -REQUEST_ALIVE

首先,日志显示的总耗时与上面网络面板截图的总耗时是吻合的,都是42.74秒,说明我们定位正确。

以下时间均以毫秒计

日志第一列为时间线,自请求发起时算。 第二列为每步操作所逝去的时间,时间差的概念,与第三列里面的dt不同,它会积累前面的耗时。 第三列为具体的事件,以及相应事件的耗时dt,此耗时为绝对耗时。

+号对应事件开始,-号对应事件结束,也就是说他们必然成对出现。住里是展开后更加详细的子事件。直到不能再细分。

如果说一开始接触到这个日志时手足无措的话,我们来看一下正常情况下的日志是怎样的,有对比才有发现。

以下随便摘取一次正常请求的日志,如下:

384462: URL_REQUEST
http://qa.tieba.baidu.com/release/getReleaseHistory?projectId=fum1.0.593
Start Time: 2015-01-03 20:23:54.698

t=1556 [st=  0] +REQUEST_ALIVE  [dt=172]
t=1556 [st=  0]    URL_REQUEST_DELEGATE  [dt=0]
t=1556 [st=  0]   +URL_REQUEST_START_JOB  [dt=171]
                   --> load_flags = 335609856 (BYPASS_DATA_REDUCTION_PROXY | MAYBE_USER_GESTURE | VERIFY_EV_CERT)
                   --> method = "GET"
                   --> priority = "LOW"
                   --> url = "http://qa.tieba.baidu.com/release/getReleaseHistory?projectId=fum1.0.593"
t=1557 [st=  1]     +URL_REQUEST_DELEGATE  [dt=4]
t=1557 [st=  1]        DELEGATE_INFO  [dt=4]
                       --> delegate_info = "extension Tampermonkey"
t=1561 [st=  5]     -URL_REQUEST_DELEGATE
t=1561 [st=  5]      HTTP_CACHE_GET_BACKEND  [dt=0]
t=1561 [st=  5]      HTTP_CACHE_OPEN_ENTRY  [dt=1]
                     --> net_error = -2 (ERR_FAILED)
t=1562 [st=  6]      HTTP_CACHE_CREATE_ENTRY  [dt=0]
t=1562 [st=  6]      HTTP_CACHE_ADD_TO_ENTRY  [dt=0]
t=1562 [st=  6]      URL_REQUEST_DELEGATE  [dt=0]
t=1562 [st=  6]     +HTTP_STREAM_REQUEST  [dt=2]
t=1564 [st=  8]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                       --> source_dependency = 384467 (HTTP_STREAM_JOB)
t=1564 [st=  8]     -HTTP_STREAM_REQUEST
t=1564 [st=  8]     +HTTP_TRANSACTION_SEND_REQUEST  [dt=1]
t=1564 [st=  8]        HTTP_TRANSACTION_SEND_REQUEST_HEADERS
                       --> GET /release/getReleaseHistory?projectId=fum1.0.593 HTTP/1.1
                           Host: qa.tieba.baidu.com
                           Connection: keep-alive
                           Accept: application/json, text/plain, */*
                           User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
                           Referer: http://qa.tieba.baidu.com/project/
                           Accept-Encoding: gzip, deflate, sdch
                           Accept-Language: en-US,en;q=0.8
                           Cookie: [2642 bytes were stripped]
t=1565 [st=  9]     -HTTP_TRANSACTION_SEND_REQUEST
t=1565 [st=  9]     +HTTP_TRANSACTION_READ_HEADERS  [dt=161]
t=1565 [st=  9]        HTTP_STREAM_PARSER_READ_HEADERS  [dt=160]
t=1725 [st=169]        HTTP_TRANSACTION_READ_RESPONSE_HEADERS
                       --> HTTP/1.1 200 OK
                           Date: Sat, 03 Jan 2015 12:23:54 GMT
                           Content-Type: application/json; charset=UTF-8
                           Transfer-Encoding: chunked
                           Connection: keep-alive
                           Cache-Control: no-cache
                           tracecode: 14346880480340800522010320
                           tracecode: 14346880480253893130010320
                           Server: Apache
t=1726 [st=170]     -HTTP_TRANSACTION_READ_HEADERS
t=1726 [st=170]      HTTP_CACHE_WRITE_INFO  [dt=0]
t=1726 [st=170]      HTTP_CACHE_WRITE_DATA  [dt=0]
t=1726 [st=170]      HTTP_CACHE_WRITE_INFO  [dt=0]
t=1726 [st=170]     +URL_REQUEST_DELEGATE  [dt=1]
t=1726 [st=170]        DELEGATE_INFO  [dt=1]
                       --> delegate_info = "extension Tampermonkey"
t=1727 [st=171]     -URL_REQUEST_DELEGATE
t=1727 [st=171]   -URL_REQUEST_START_JOB
t=1727 [st=171]    URL_REQUEST_DELEGATE  [dt=0]
t=1727 [st=171]    HTTP_TRANSACTION_READ_BODY  [dt=0]
t=1727 [st=171]    HTTP_CACHE_WRITE_DATA  [dt=1]
t=1728 [st=172]    HTTP_TRANSACTION_READ_BODY  [dt=0]
t=1728 [st=172]    HTTP_CACHE_WRITE_DATA  [dt=0]
t=1728 [st=172] -REQUEST_ALIVE

针对上面正常的请求,我们主要关注两部分,如下面的截图:

  • 发送请求头 ` +HTTP_TRANSACTION_SEND_REQUEST [dt=1]`
  • 读取响应头 ` +HTTP_TRANSACTION_READ_HEADERS [dt=161]`

这是正常的情况下,没有什么问题。并且日志里可以清晰地看到发送的请求头是什么,然后解析出来的响应头是什么。这跟在网络面板看到的是一致的。

再回到出问题的请求日志上来,同样我们只关注这两部分。如下面的截图:

与正常相比,最后一次发送请求和读取响应头无异常,时间就多在了前面还有再次发送和请求的过程,细看时间都花在了以下两个事件中:

  • HTTP_STREAM_PARSER_READ_HEADERS [dt=21301]
  • HTTP_STREAM_PARSER_READ_HEADERS [dt=21304]

该事件的名称已经自我解读,意思是解析读取的响应头。但问题是紧接着下面报错了,

--> net_error = -101 (ERR_CONNECTION_RESET)

读取响应头时发生了链接重置的错误,有理由认为本次链接是不成功的,没拿到正确的响应头,于是解析不成功。时间都花在了这里,足足21秒之久,两个21秒造就了上面看到的Stalled了42秒之久。

问题似乎已经很明朗了。链接被重置。

在第三次尝试的时候正常了,于是正确返回,我们才看到了被解析的响应头被展示在了下面。也就是说在出问题的时候要么响应头未拿到,要么响应头非法导致解析不成功。而原因就是链接被重置。

那么接下来的工作就是对ERR_CONNECTION_RESET这个错误的追查了。

官方关于 ERR_CONNECTION_RESET 错误的解释

未找到官方相应的资料,Chrome官网上唯一关于此错误的描述是在安装Chrome时出现Error 101。我估计文档的撰写人员没想到谁会这么蛋疼想要看这些生涩的东西,除了开发者。既然你都是开发者了,那为什么不去看Chromium的源码。

好吧,唯一的途径似乎只能从源码中寻找了。作为只精JS的前端人员,现在要从C,C++代码中找答案了。估计追完这个问题,我会尝试为Chromium贡献代码。

慢着,在这之前,还是搜到一些关于这个错误的信息的。但似乎都不怎么靠谱。

比如这里提到,是因为ISP网络问题,实在无太可能。还有这是神马居然一个硬件网站但提到了这个错误,并且怀疑是杀软导致Chrome出问题,但杀软已经在上文被我们排除了。

Chromium 源码

那么这个错误究竟是什么。能不能找到点靠谱的解释。当然能,让我们进入到Chromium的源码中去。

ERR_CONNECTION_RESET被唤起的地方

在Chromium的源码中搜索该常量名,确实出现很多结果。联系到我们查看日志发现问题的上下文,是在解析响应头报的。所以我们定位到http_stream_parser.cc文件,同时注意到有一个文件叫net_errors_win.cc,所以猜测他是定义所有错误常量用的,也顺便打开之。

经过观察src/net/base/net_errors_win.cc 其路径和代码得知其中多为系统级别的错误,似乎跟我们的问题不是很关联,忽略该文件。

http_stream_parser.cc文件中,ERR_CONNECTION_RESET仅出现一次。这给我们定位带来了极大的便利。

[chromium]//src/net/base/net_errors_win.cc:

// Returns true if |error_code| is an error for which we give the server a
// chance to send a body containing error information, if the error was received
// while trying to upload a request body.
bool ShouldTryReadingOnUploadError(int error_code) {
  return (error_code == ERR_CONNECTION_RESET);
}

这里定义了一个ShouldTryReadingOnUploadError 的方法,注释耐人寻味,这个时候,这样的情景,能否正确解读注释成为了比读懂代码更重要(这是我在看JS代码时永远无法体味到的感觉),下面尽可能对它进行理解:

在尝试发送一个请求体的时候,让服务器尝试发送一个带错误的响应体,如果我们接收到了该错误则返回true

我承认被上面的复杂从句打败!

那么我们来看这个方法被调用的场景。

现在我们点击上面的ShouldTryReadingOnUploadError方法,代码下方出现调用了该方法的地方,一共有两处。

分别点击进行查看。

459行DoSendHeadersComplete方法里进行了调用:

int HttpStreamParser::DoSendHeadersComplete(int result) {
  if (result < 0) {
    // In the unlikely case that the headers and body were merged, all the
    // the headers were sent, but not all of the body way, and |result| is
    // an error that this should try reading after, stash the error for now and
    // act like the request was successfully sent.
    if (request_headers_->BytesConsumed() >= request_headers_length_ &&
        ShouldTryReadingOnUploadError(result)) {
      upload_error_ = result;
      return OK;
    }
    return result;
  }

虽然不太可能,但也不排除头部和请求体合并的情况,当所有头部发送完毕,请求体不一定,此时result便是需要稍后处理的一种错误,这里暂且先返回OK

516行另一个DoSendBodyComplete方法里进行了调用:

int HttpStreamParser::DoSendBodyComplete(int result) {
  if (result < 0) {
    // If |result| is an error that this should try reading after, stash the
    // error for now and act like the request was successfully sent.
    if (ShouldTryReadingOnUploadError(result)) {
      upload_error_ = result;
      return OK;
    }
    return result;
  }

跟上面类似,如果result出错,稍后处理,先返回正常

这也与我们在日志中看到的情况相符,在前面再次错误后,这次请求并没有终止结束,而是尝试到了第三次并且以成功结束的。

但不管怎样,从这两个方法,一个DoSendHeadersComplete, 另一个DoSendBodyComplete,身上能体现出请求确实已经发出去。

TCP RST

另外,在net_error_list.h这个文件的109行,可以准确找到我们在日志中得到的101号错误。它的定义如下:

// A connection was reset (corresponding to a TCP RST).
NET_ERROR(CONNECTION_RESET, -101)

从括号中的进一步解释可以知道,它代表TCP连接重置。

TCP

那么问题来了,什么是TCP连接重置?什么会引发TCP连接重置。从这篇文章中有比较详细的解答。

想要完全解释,本文似乎是不可能的了。但根据上面的文章,这里可以简单转述一下。

什么是TCP连接

它是一种协议。当网络上一个节点想与另一个节点通信时,双方需要选建立连接。而这个连接过程需要大家都懂的一种约定,TCP就是事先定好的一种约定,于是我们采用它吧,于是其中一个节点按照这个约定发起一建立连接的请求,另一节点收到后,根据该约定,便能读懂这个请求里各字段的意思:哦,丫这是想约我呢。

三次握手

继续上面的例子。A想与B通信,并且使用TCP。

首先A发起一个报文,其中包含自己的地址,想要连接的目标地址,自己用来连接的端口及目标机器的端口,etc.

B收到邀约,并且愿意付约。此刻B需要回传一个报文,告诉A我愿意跟你连接。

A收到B的肯定应答,到此A与B经历了三次通信或者说是握手,双方都没有异议,连接建立。

而连接断开的过程也颇为类似。双方中的一方比如说A先发起一个断开连接的报文FIN,B收到并确认,然后回传一个可以断开的报文FIN给A。此刻A收到并确认。此刻双方都确认后,连接可以安全断开,但还会保持一个等待断开的状态,大概持续4分钟,用于之前连接通路上未传输完成的数据进行善后。

什么是重置

上面提到了4分钟的等待时间,而重置RESET便是立即断开连接的手段。

发生重置的情况

到此重置的作用已然明了。也就是说,重置甚至算不上一个错误,它是TCP连接中的一种正常情况。但什么时候会发生重置,如何引起的。

上文列出了三种情况。

SMB Reset

简单举例来说,服务器提供了两个端口445,139进行服务,客户端同时去请求与这两个端口连接,服务器返回了两个端口可以被连接,此刻客户端择优选择一个进行连接,而重置另一个。

Ack, Reset

报文重置发生主要有以下情况: – 服务器没有监听被请求的端口,无法建立连接 – 服务器此刻无法比如没有充裕的资源用来连接连接

TCP Reset due to no response

由于没有响应而被重置。当发起连接的一方连续发送6次请求未得到回应,此刻默认他们之间已经通过三次握手建立了连接并且通信有问题,发起的一方将连接重置。

Application Reset

除了上面的情况,找不到TCP内部自己发送的重置,则归为了这一类。程序内将连接重置。此种情况包含了所有你想得到想不到将连接断开的情况。有可能是程序内部逻辑重置的,所以不能完全认为此时发生了错误。

值得注意的是,上面列出的情况服务器的不确定性导致连接重置的可能性要合理些。Chrome 主动发起URL请求不太可能自己又重置掉,并且没有理由重置掉后又去重连。

进一步解读日志文件

上面Chromium源码部分的求证多少带有猜测成分。不妥。

因为没找到关于Chrome net-internal 日志的官方文档什么的,自身去解读始终是有局限的。不如提个ISSUE让Chromium开发人员来搭一把手吧。遂向Chromium提交ISSUE,请戳此查看,虽然我不认为现在遇到的这个问题跟Chrome有关并且属于Chrome的Bug,目的仅仅是看他们能否帮忙给出合理的日志解读来定位问题。

三天后(有点热泪盈眶),有同学回复,将日志所体现的问题诊断得似乎很有道理,可信。

1) We have a bunch of connections to qa.tieba.baidu.com, all were used successfully, and are now idle. 2) They all silently die for some reason, without us ever being informed. My guess is your personal router times out the connection, but this could also be your ISP, the destination server, or ever a real network outage (A short one) that prevents us from getting the connection closed message. 3) There’s a new request to qa.tieba.baidu.com. We try to reuse a socket. After 21 seconds, we get the server’s RST message (“I don’t have a connection to you.”). Since it was a stale socket, we’re aware this sometimes happens, so we just retry…And get the next idle socket in the list, which, after 21 seconds, gives us the same reset message. We try again, for the same reason. This time we don’t have another stale socket to try, so we use a fresh one. The request succeeds.

The real problem here is something is taking 21 seconds to send us the RST messages, despite the fact that a roundtrip to the server you’re talking to only takes about 100 milliseconds.

  • 「之前有过很多成功的连接」,确实,因为出现加载缓慢的情况是偶发的,这之前有过很多正常的不卡的请求存在过。这里没有异议。
  • 「他们都以未知的原因被断掉了」,因为不是正常地断开连接,所以客户端也就是浏览器不知道当前与服务器的TCP连接已经断开,傻傻地保留着与服务器连接的socket,注意,此时已经发生信息的不对等了,这是问题的根源。至于什么原因,给出了可能的原因:路由器认为连接超时将其断掉,同时不排除ISP(互联网服务提供商)的原因,服务器暂时的停运抽风等。不管怎样,客户端浏览器没有收到连接断开的信息。
  • 在上面的基础上,我们去发起一次新的请求。此时浏览器希望重用之前的连接以节省资源,用之前的一个socket去发起连接。21秒后收到服务器返回的重置信息(意思是服务器告诉浏览器:我和你之间没有连接),没关系,上面提到,我们有很多可以重用的连接,于是浏览器重新从可用的连接里面又选择了一个去进行连接,不幸的是,同样的情况再次发生,21秒后收到服务器的重置信息。这体现在日志上就是第二次重试失败。到第三次,因为前面浏览器认为可以重用的连接现在都被正确地标为断开了,没有新的可用,于是这次浏览器发起了全新的请求,成功了!

总结出来,两个问题:

  • 为什么之前成功的连接不正常的断开了?服务器配置或者网络原因?
  • 是什么让浏览器21秒后才收到重置信息?服务器作出反应过慢还是网络原因?

Chrome Dev Tool 中时间线各阶段代表的意义

另附注一下Chrome Dev Tool 中请求的时间线各阶段代表的意义。 以下内容扒自Chrome 开发者文档页,然后我将它本地化了一下下。

Stalled/Blocking

在请求能够被发出去前的等等时间。包含了用于处理代理的时间。另外,如果有已经建立好的连接,那么这个时间还包括等待已建立连接被复用的时间,这个遵循Chrome对同一源最大6个TCP连接的规则。

「拿我们的情况来说,上面出错所有的耗时也是算在了这部分里面。网络面板中显示的其余时间比如DNS查找,连接建立等都是属于最后那次成功请求的了」

Proxy Negotiation

处理代理的时间。

DNS Lookup

查找DNS的时间。页面上每个新的域都需要一次完整的寻路来完成DNS查找。

Initial Connection / Connecting

用于建立链接的时间,包括TCP握手及多次尝试握手,还有处理SSL。

SSL

完成SSL握手的时间。

Request Sent / Sending

发起请求的时间,通常小到可以忽略。

Waiting (TTFB)

等待响应的时间,具体来说是等待返回首个字节的时间。包含了与服务器之间一个来回响应的时间和等待首个字节被返回的时间。

Content Download / Downloading

用于下载响应的时间

结论

我相信很多同学是直接跳到这里来了的。事实上我给不出什么解决方案,但能排除前端代码引起问题的可能性。

具体来说,能够得到的结论有以下几点:

  • 请求成功构造,失败情况下也可以看到正常的请求头被打印出来了的
  • 可以肯定的是在与服务器建立连接时被Shut down了,参考上面关于连接重置的部分会更有意义一些
  • 参考上面「进一步解读日志文件」部分,来自Chromium开发者的回复中对日志文件的解读更加合理些,浏览器与服务器的连接不正常断开是导致问题的根源,以至于影响了后面对连接的重用
  • 21秒的等待仍然是个未知数,不知道有何不可抗拒的外力促使浏览器21秒后才收到服务器的重置信息。此处浏览器与服务器的失联原因有待查证

最后寄希望于RD同学跟进,协助排查服务器连接及后端代码的部分。FE同学会保持持续关注。

参考及引用

#1 Chrome stalls when making multiple requests to same resource?

#2 What does “pending” mean for request in Chrome Developer Window?

#3 Evaluating network performance / Resource network timing

#4 Provisional headers are shown

#5 “CAUTION: provisional headers are shown” in Chrome debugger

#6 Chrome 里的请求报错 “CAUTION: Provisional headers are shown” 是什么意思?

#7 Issue 345643003: Http cache: Implement a timeout for the cache lock

#8 Issue 46104: Pages can get blocked in “Waiting for Cache” for a very long time

#9 Providing Network Details for bug reports

#10 从FE的角度上再看输入url后都发生了什么

#11 ERR_CONNECTION_RESET 的Chromium 源码

#12 Chromium Network Stack

#13 Where do resets come from? (No, the stork does not bring them.)

#14 Issue 447463: Chrome-network: Long delay before RST message on stale sockets results in slow page loads)

作者:wayou (http://wayou.github.io/) – IT重度症需要治疗
分类: CMS开源系统 标签:

网页加载waiting(TTFB)时间过长

2016年5月12日 评论已被关闭

网页加载waiting(TTFB)时间过长

http://www.alimove.com/software/776.html

今天在打开此WordPress网站后台时,网页加载速度超级慢,使用chrome浏览器‘审查元素’功能,得到如下结果,目前还不知道如何去解决,等解决之后,我再把解答的方法写上来。

关于此问题的详细剖析,请戳这里

也可以戳这里,TTFB-首字节时间

网页加载waiting(TTFB)时间过长 - 第1张  | 和美视界

分类: CMS开源系统 标签:

TTFB简介

2016年5月12日 评论已被关闭

TTFB
http://baike.baidu.com/link?url=KqCC6a0fWwmZJcSDXYAE4WH-AjYVjpSZUe4GmqxL3ajQoneCjHtfTO2UMaMnxkgrMOu3xB8FGGHn1VwncVSEd_
TTFB 属性
Application Center Test
TTFB 属性
获取在接收到响应的首字节前花费的毫秒数。
lTime = Response.TTFB
返回值 lTime As Long:首字节响应时间(以毫秒为单位)。
TTFB:httpwatch的timechart中的一列参数。
TTFB (Time To First Byte),是最初的网络请求被发起到从服务器接收到第一个字节这段时间,它包含了 TCP连接时间,发送HTTP请求时间和获得响应消息第一个字节的时间。

分类: CMS开源系统 标签:

靠谱的国内前端CDN公共库(替代GoogleAPIs的加速节点)

2016年5月12日 评论已被关闭

靠谱的国内前端CDN公共库(替代GoogleAPIs的加速节点)

http://www.xxsay.com/archives/678

最近一段时间,由于政策原因造成Google被严重干扰。GoogleApis已经不能正常使用,部分网页中的ajax.googleapis.com和fonts.googleapis.com访问速度过慢,拖慢整个网页速度。

可以替代GoogleAPIs的方案:

1、使用官方的源。如Jquery官方CDN:http://code.jquery.com/

2、把涉及的JS/CSS放到自己服务器上。

3、改为国内CDN节点。

这也是本文的主要内容,下面介绍一些各大靠谱CDN公共库:

国外

微软(Microsoft ASP.net CDN):http://www.asp.net/ajaxlibrary/CDN.ashx   (支持https)

CDNJS.com提供的100多种JS库:http://cdnjs.com/  (支持https)

国内

又拍云:http://jscdn.upai.com/ (支持https)

又拍云 CDNJSCN:http://www.cdnjs.cn/ (支持https)维护者(Sofish/hfcorriez/ikbear@qiniu)

中科大库:https://servers.ustclug.org/2014/07/ustc-blog-force-google-fonts-proxy/ [支持https,完全GoogleAPIs镜像] 维护者(LUG@ustc)

新浪云:http://lib.sinaapp.com/ (支持https,但库不全不新)

百度云:http://developer.baidu.com/wiki/index.php?title=docs/cplat/libs [不推荐,不支持https]

360卫士:http://libs.useso.com/  [不推荐,不支持https]

七牛CDN  StaticFile:http://www.staticfile.org/ [不推荐,不支持https] 维护者(Sofish/hfcorriez/ikbear@qiniu)

 

————————–以下内容可以不看———————————

什么是CDN公共库?

CDN公共库是指将常用的JS库存放在CDN节点,以方便广大开发者直接调用。与将JS库存放在服务器单机上相比,CDN公共库更加稳定、高速。一般的CDN公共库都会包含全球所有最流行的开源JavaScript库。
为什么要引用CDN公共库?

1.减少等待时间

CDN-Content Delivery Network(内容分发网络),通过各种各样的服务途径把你的一些静态内容分散开来,当用户的浏览器提交这些文件的链接请求,他们便会自动下载网络上最近的可用的文件。这样任何使用你的服务的用户从JS库下载都将获得比从你自己的服务器上下载更快的速度。

2.增加网页的同时载入速度

为了避免服务的过载,浏览器限制了同时连接的数目,依据不同的浏览器,这个限制可能是每个机房仅仅两个之少。
使用CDN公共库加载JS,使你本地服务器上更多服务可以同时进行。

3.更好的缓存

使用CDN公共库的最大好处是你的用户可能根本不需要下载jQuery.不论你的缓存多么强大,如果你用自己的服务器提供jQuery,那么你的用户至少要下载一次它,某个用户很有可能在他们浏览器的缓存区里下载了许多完全相同的jQuery.min.js的拷贝版本,但是当他们第一次访问你的网站的时候,这些拷贝版本会被忽略。

而当浏览器检测到同样版本的指向CDN公共库的链接,它就会知道这是下载同一个文件,不仅是CDN公共库的服务器会返回一个304(不需要修改文件的指令,即服务器上的文件未改动过)来回复一个重复的请求,而且会命令浏览器的缓存该文件长达一年的时间。

这意味着即使一些人访问了数百的使用CDN公共库的网站,他们只需要下载一次就够了。

 

http://fonts.googleapis.com/css?family=Open+Sans%3A300italic%2C400italic%2C600italic%2C300%2C400%2C600&subset=latin%2Clatin-ext&ver=4.4Google本身的应该可以打开了,有国内CDN了。貌似不用360的这个了。

分类: CMS开源系统 标签:

(http://fonts.googleapis.com/css?)打开很慢解决方案

2016年5月12日 评论已被关闭

(http://fonts.googleapis.com/css?)打开很慢解决方案

http://blog.csdn.net/a6225301/article/details/41115323

最近,有网友反映称谷歌官网域名google.com、谷歌香港google.com.hk都打不开, ping了一下google.com和google.com.hk两个域名的服务器情况,最后ping出来的IP地址均显示为“美国”,也就是说谷歌香港(google.com.hk)的服务器,已由香港转移至美国,所以链接时间会很长,甚至断断续续出现请求超时的情况。

\

图:google.com.hk域名服务器ping测结果

   Google服务在大陆的崩溃情况不仅影响到了广大网民,也影响到了数百万的站长。WordPress是世界上最大的开源博客程序,而WordPress大部分的主题都在使用Google的在线字体方案——Google Fonts,Google服务一不稳定,大量的独立博客字体就加载不出来,直接导致了几十万独立博客打开速度令人无法忍受,严重的时候会导致网站打不开。

\

图:Google字体打开时间19秒

   为此,360网站卫士推出一项字体加速服务,站长只要修改一行代码,就可以免费使用到由360网站卫士CDN加速的字体服务。

修改方法如下:

打开wordpress代码中的文件wp-includes/script-loader.php文件,搜索:fonts.googleapis.com找到这行代码:

$open_sans_font_url = “//fonts.googleapis.com/css?family1=Open+Sans:300italic,400italic,600italic,300,400,600⊂=$subsets”;

\

把fonts.googleapis.com替换为fonts.useso.com

\

   修改完保存,再次刷新,大家就可以发现,自己的网站速度已经比以前快了很多,几乎瞬间就可以拿到Google字体了。原因就是本来需要从美国服务器才能拿到的google字体,现在已经遍布360全国的机房了。

\

欢迎大家试用我们的新福利。

   如果各位站长想要更威猛的加速效果,使用专业的加速解决方案,只需要登陆360网站卫士官网(wangzhan.360.cn),申请加入即可。

分类: CMS开源系统 标签:

WordPress全自动将远程图片本地化插件

2016年5月12日 评论已被关闭

WordPress全自动将远程图片本地化插件

http://www.5yun.org/4682.html

文章是网站的血液,通过源源不断的更新站点内容才能让网站维持活力,让访客每次来访都有新鲜可阅读的新资讯才能增加访客的粘性,不断增添新的内容对网站SEO优化也是非常有必要的;
能够不断原创文章当然是最好的,不过一个人的精力是有限的持续不断有大量原创更新很多时候也不太现实;
通过用户投稿,转载一些文章内容也是扩充丰富站点内容的重要方式;
采用站外文章时,经常会遇到一些远程图片问题,要知道绝大部分站点寿命都是不长久的或者做了防盗链措施,如果不将远程图片本地化存储在自己的服务上那么很容易出现图片加载失效的情况出现,这势必造成死链一是对搜索引擎不友好,二是造成加载缓慢;
刚好今天公司的一批WordPress站点需要将远程本地化存储处理,将第三方图片链接全部保存在自己服务上面;
通过一番查找和测试最终选择了【DX auto save images】这款插件
测试环境:WordPress 4.0 Nginx 1.2.9+MySQL 5.5.34+PHP 5.3.27

设置使用非常简单

WordPress全自动将远程图片本地化插件

在后台侧边栏设置一下属性,以后WordPress就按照此设置自动本地化存储了;
很可惜“大侠”这个插件的作者个人博客关闭了,site也查询不到收录信息,我就把插件中一些失效的链接描述作者推广信息精简删除掉了只保留作者的联系QQ号码;

DX auto save images下载地址:http://pan.baidu.com/s/1c0hF3MS

分类: CMS开源系统 标签:

解决wordpress自动升级后,后台打不开的问题

2016年5月12日 评论已被关闭

解决wordpress自动升级后,后台打不开的问题

http://www.wpmee.com/auto-wordpress/

前话

今天早上 起来发现wordpress发来了邮件,这家伙又偷偷的升级到了wordpress3.8.3,心中还暗自窃喜,自动升级真好使啊。但是发现评论里有一些垃圾评论,正当我点击删除的时候,wordpress提升:数据库已经是最新版本,无需升级。

尼玛,我知道是最新版啊!

我要进后台啊!

尼玛一直提示,有完没完!

好吧。。。不让进,为毛呢?于是网上搜索了一番,发现 了解决方法,做个记录吧,如果你也遇到此类情况可以试一试下面的方法。

解决方法

出现此类问题,大多数是缓存引起的,如果你装了什么缓存插件或者是启用了什么 缓存脚本你可以仔细检查一下了,比如什么hyper cache,fix什么的以及wp super cache等等,检查你的wp-content文件夹目录下是否有一些缓存专用的 文件,例如:

object-cache,本站就是次文件引起的,原为一个数据库缓存查询的插件,删除此文件就 OK了。

当然如果你觉得自动更新不好使,你可以禁用自动更新以及其他禁止更新的小细节,详细参考此文:

WordPress 后台自动更新详解和设置

分类: CMS开源系统 标签: