Start

感谢小伙伴们,使用权那他开发的南博app。

南博app,做为一个面向博主的app,从开发版到现在历时了240多天,版本迭代也很快。

从以前的无法安装,到现在的可以安装。从以前的闪退,到现在的相对稳定。
权那他也是励志开发一个功能齐全且有特色的typecho客户端。从v1.5版本开始引入了会员,即南博会员.
为什么呢?因为权那他其实也是个学生,并不是每天都有时间去开发和debug,南博app开发,费劲了权那他很多时间个精力。所以,觉得,再v1.5开始,后续开发的功能对南博会员专享。

Load

最近,很多小伙伴们,反馈,要么是发布文章失败,要什么是评论失败。或者说,很多操作是操作是成功的,但是南博会报错。
然后我发现了一篇文章来自迷你日志的 Typecho使用南博客户端发布文章失败 中了解到启用了老高的Tpcache插件到导致很多失败问题.
然后迷你日志也给了解决办法,从网上找到Tpcache的替代版:TpCache 魔改版

分析原因

我们查看Tpcache插件的源码https://github.com/phpgao/TpCache/blob/master/Plugin.php 在25、26行发现

Typecho_Plugin::factory('index.php')->begin = array('TpCache_Plugin', 'C');
Typecho_Plugin::factory('index.php')->end = array('TpCache_Plugin', 'S');

可知,在index.php中的

/** 注册一个初始化插件 */
Typecho_Plugin::factory('index.php')->begin();  //  这里执行了 Tpcache 的 C

/** 开始路由分发 */
Typecho_Router::dispatch();

/** 注册一个结束插件 */
Typecho_Plugin::factory('index.php')->end();    //  这里执行了 Tpcache 的 S

Typecho_Plugin::factory('index.php')->begin(); eval 了 Tpcache 的 C 方法

Typecho_Plugin::factory('index.php')->end(); eval 了 Tpcache 的 S 方法

我们在https://github.com/phpgao/TpCache/blob/master/Plugin.php 第162行,的 public static function C(){...}

165行到168行

// 插件初始化
if (!self::init()) return false;
// 前置条件检查
if (!self::pre_check()) return false;

我们跟随 init() pre_check() 这里都初始化等等,就是判断,是否有缓存或者开始缓存。

然后198行发现 C方法的 ob_flush(); ,这个函数将送出缓冲区的内容(如果里边有内容的话)。如果想进一步处理缓冲区中的内容,必须在ob_flush()之前调用ob_get_contents() ,因为在调用ob_flush()之后缓冲区内容将被丢弃。

然后278行发现 S方法的$html = ob_get_contents(); 好了,Tpcache的缓存内容就是这几个代码

但是,我们发现388行

//判断是否需要缓存
if (!self::needCache($pathInfo)) return false;

有判断是否需要缓存,我们更近needCache(),240行

//action动作不缓存
$pattern = '#^/action#i';
if (preg_match($pattern, $path)) return false;

这里有判断action动作,若是就不起效。显然这里有判断,那么是其他什么地方导致的呢?

问题

为什么缓存会导致失败呢?

你想,既然是缓存插件,那么缓存原则是,一个请求地址,如果没有缓存的静态内容,就开始原路运行,然后结果缓存到一个文件夹。如果有缓存内容,就直接加载缓存的文件夹相应的内容。

而南博调用的是博客的xmlrpc地址,是的。xmlrpc是恒定了,一般为https://domain.cn/aciton/xmlrpc 请求方式是post,那么如果你开启了缓存插件.
那么,比如,你第一次登录南博,是成功的。进入了南博主页面,南博要加载其他的内容,需要再次请求,还是那个请求地址,那么,缓存插件会返回登陆时的数据。和南博主页面需要的数据类型不一样,就会闪退,失败等等。

而,上述的Tpcache插件,对aciton动作不生效即不缓存的。那么什么地方出问题了。

真相大白

有点小伙伴说,发文章和回复评论,是发出去了,但是显示失败。

发现第33行

//评论
Typecho_Plugin::factory('Widget_Feedback')->finishComment = array('TpCache_Plugin', 'comment_update');

注册了回调。

回调的是345行的

public static function comment_update($comment){
        $req = new Typecho_Request();
        // 获取评论的PATH_INFO
        $path_info = $req->getPathInfo();
        // 删除最后的 /comment就是需删除的key
        $article_url = preg_replace('/\/comment$/i','',$path_info);

        self::init($article_url);
        
        self::delete($article_url);
}

这里,有getPathInfo 排除action/xmlrpc的动作

同样 第28行

  //页面编辑
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->finishPublish = array('TpCache_Plugin', 'post_update');
Typecho_Plugin::factory('Widget_Contents_Page_Edit')->finishPublish = array('TpCache_Plugin', 'post_update');

这里也注册了文章发布回调。

回调的是297行

public static function post_update($contents, $class)
{
    if ('publish' != $contents['visibility'] || $contents['created'] > time()) {
            return;
    }
}

这里也没有排除action/xmlrpc的动作

即使index.php 中对action行动有判断,但是在回调方法中没有对action行动进行判断

故上述回调没有配出action/xmlrpc动作,导致xmlrpc返回的数据有问题,故而文章,评论是成功的,但是南博提示是错误的。

解决办法

这里列出连两个解决方法,欢迎朋友们给出你们的解决方案

  • 方法1. 要么是在上述的回调方法中加入对action/xmlrpc动作的判断,对action行动不生效。
  • 方法2. 或者使用 TpCache 魔改版 这里的魔改版,我看了源码,对上述的写入了action动作判断,而且新增很多功能和修复了很多bug,推荐使用这个缓存插件。

其他报错问题

如果你发现了,或者也解决了相关在南博上使用的操作问题。

请在下边评论留言你的文章地址。

普遍问题

很多朋友说在南博发布文章和回复评论失败,但是已经发出去了,只是提示失败。

基本上是什么地方注册了回调方法,没有考虑到xmlpc的兼容。南博的发文件和评论回复等等,基本上是使用的typecho接口.
那么代表,在南博发文章和评论都会走那些插件的回调方法,而那些回调方法如果没有考虑到xmlrpc的action只考虑后台的action,就会有小错误。