最近在夜间编辑文章的时候明显感觉到有些文章的编辑界面打开异常缓慢,甚至出现超时失败的情况。
怀着好奇心对这个问题进行了debug。发现只要编辑带有附件的文章就会出现这种情况,当去打开【管理】中的【文件】时感觉尤为明显。经过一步步的查看源码,发现write-post.php
文件中会调用var/Widget/Abstract/Contents
中的push
函数,而push
函数调用filter
函数对数据进行处理。
/**
* 将每行的值压入堆栈
*
* @access public
* @param array $value 每行的值
* @return array
*/
public function push(array $value)
{
$value = $this->filter($value);
return parent::push($value);
}
而在filter
函数中,当发现文章出现附件时将对附件的信息进行一波处理,该文件的681
行。
/** 处理附件 */
if ('attachment' == $type) {
$content = @unserialize($value['text']);
//增加数据信息
$value['attachment'] = new Typecho_Config($content);
$value['attachment']->isImage = in_array($content['type'], array('jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp'));
$value['attachment']->url = Widget_Upload::attachmentHandle($value);
if ($value['attachment']->isImage) {
$value['text'] = '<img src="' . $value['attachment']->url . '" alt="' .
$value['title'] . '" />';
} else {
$value['text'] = '<a href="' . $value['attachment']->url . '" title="' .
$value['title'] . '">' . $value['title'] . '</a>';
}
}
而在该函数中,我们发现它调用了一个Widget_Upload::attachmentHandle
的函数,该函数的作用如下,其中如果发现定义了插件来处理上传,那么就使用插件中定义的处理函数。
/**
* 获取实际文件绝对访问路径
*
* @access public
* @param array $content 文件相关信息
* @return string
*/
public static function attachmentHandle(array $content)
{
$result = Typecho_Plugin::factory('Widget_Upload')->trigger($hasPlugged)->attachmentHandle($content);
if ($hasPlugged) {
return $result;
}
$options = Typecho_Widget::widget('Widget_Options');
return Typecho_Common::url($content['attachment']->path,
defined('__TYPECHO_UPLOAD_URL__') ? __TYPECHO_UPLOAD_URL__ : $options->siteUrl);
}
而该插件就是我目前使用的百度云存储
插件。那为什么该插件就导致文章的附件加载缓慢,甚至加载失败呢?我们继续查看该插件中的函数。在改插件中,将attachmentHandle
函数重新指向了BOSUpload_Plugin中的attachmentHandle
。
/**
* 激活插件方法,如果激活失败,直接抛出异常
*
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function activate()
{
Typecho_Plugin::factory('Widget_Upload')->uploadHandle = ['BOSUpload_Plugin', 'uploadHandle'];
Typecho_Plugin::factory('Widget_Upload')->modifyHandle = ['BOSUpload_Plugin', 'modifyHandle'];
Typecho_Plugin::factory('Widget_Upload')->deleteHandle = ['BOSUpload_Plugin', 'deleteHandle'];
Typecho_Plugin::factory('Widget_Upload')->attachmentHandle = ['BOSUpload_Plugin', 'attachmentHandle'];
Typecho_Plugin::factory('Widget_Upload')->attachmentDataHandle = ['BOSUpload_Plugin', 'attachmentDataHandle'];
}
而attachmentHandle
的工作就是对百度对象存储进行初始化,然后调用getObjectUrl
获取文件的url
地址。
/**
* 获取实际文件绝对访问路径
*
* @access public
* @param array $content 文件相关信息
* @return string
*/
public static function attachmentHandle(array $content)
{
$bos = self::bosInit();
return $bos->getObjectUrl($content['attachment']->path);
}
我们继续查看bosInit
函数,该函数每次回去百度云存储的网址进行获取句柄,这些已经发现了一个问题了。对于编辑的文章来说,一个文章带有的附件有多个,那么在编辑文章界面打开时,如果有N个附件将会调用N次附件URL转换函数,而该函数将会调用N次百度云存储的实例初始化,这样显然会拖慢整个页面的执行速度。而根据设计模式而言,这里显然只需要一个实例,所以在获取实例这里可以直接进行单例模式设计即可。
而问题远远不止如此,另一个原因是我的网站是在国外的,在晚上登上网站所在的vps ping了下百度云存储所在地址iotshare.su.bcebos.com
,慢就算了还可以接受,竟然会丢包!
不能忍,于是再次弃坑百度云存储。