优化朋友圈

博客自从添加了朋友圈功能,优化就一直没有停止过,但是近2年下来,一直不满意,主要是前台打开页面等待速读太长。太长的原因是因为需要在后台获取目标网站的feed内容后才可以读取,随着友链网站越来越多,等待的时间也会越来越长。

前两天浏览我心向阳的博文《创建一个定时任务刷新订阅缓存》,给我很大的启发。我能否把现有的朋友圈代码分为2个独立的文件,一个文件用来后台获取友链feed并写入redis,另外一个文件用来前台直接读取redis并展示。我现在的朋友圈定的是2小时更新一次,所以后台获取只要提早2分钟也就是在1小时58分钟时获取一次,这样除非是在获取的时间内访问网站,其他时间段基本都能快速打开前台页面,我试了试,比着以前的访问速度真的是有了质的提升。

重新布置朋友圈代码如下:

1、在pix/page目录下也就是朋友圈页面friends.php的同级,建立rsscache.php用来后台获取友链网站的feed内容,在保存到pix/rsscache目录下的同时写入到redis。rsscache.php代码如下:

<?php
// 手动指定 wp-load.php 文件的完整路径,可以是绝对路径,也可以是相对路径,下面一句为例子
require_once('../../../wp-load.php');

// 配置信息
define('TIMEZONE', 'Asia/Shanghai');
define('CACHE_UPDATE_INTERVAL', 2 * 3600); // 缓存更新间隔,单位:秒
define('CACHE_DIR', get_stylesheet_directory(). '/rsscache/');
define('REDIS_HOST', '127.0.0.1');
define('REDIS_PORT', 6379);

date_default_timezone_set(TIMEZONE);

// 引入 SimplePie 类
require_once(ABSPATH. WPINC. '/class-simplepie.php');

// 验证链接格式是否合法
function is_valid_url($url) {
    return filter_var($url, FILTER_VALIDATE_URL)!== false;
}

// 封装文件读写操作
function read_file($file_path) {
    return file_exists($file_path)? file_get_contents($file_path) : false;
}

function write_file($file_path, $content) {
    return file_put_contents($file_path, $content);
}

// 缓存友情链接信息
function get_cached_friend_links() {
    $links_key = 'friend_links';
    $links = get_transient($links_key);
    if (!$links) {
        $links = get_bookmarks([
            'orderby' => 'name',
            'category' => 0,
            'order' => 'ASC',
            'hide_invisible' => 1,
            'categorize' => 0,
            'title_li' => '',
            'echo' => 0
        ]);
        set_transient($links_key, $links, 3600); // 缓存 1 小时
    }
    return $links;
}

// 获取 Redis 实例
function get_redis_instance() {
    static $redis = null;
    if ($redis === null) {
        $redis = new Redis();
        try {
            $redis->connect(REDIS_HOST, REDIS_PORT);
        } catch (Exception $e) {
            error_log("Redis 连接错误: ". $e->getMessage());
            $redis = null;
        }
    }
    return $redis;
}

// 获取 RSS 内容,优化错误处理
function get_rss_content($feed_url) {
    $response = wp_safe_remote_get($feed_url, ['sslverify' => true, 'timeout' => 10]);
    if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
        return wp_remote_retrieve_body($response);
    }
    $response = wp_safe_remote_get($feed_url, ['sslverify' => false, 'timeout' => 10]);
    if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
        return wp_remote_retrieve_body($response);
    }
    error_log("无法从提供 RSS 的 URL: {$feed_url} 获取 RSS 内容,错误信息: ". print_r($response, true));
    return '无法从提供 RSS 的 URL 获取 RSS 内容。';
}

// 处理 RSS 内容,删除指定标签及部分内容
function process_rss_content($rss_content) {
    $rss_content = preg_replace('/<category.*?<\/category>/is', '', $rss_content);
    $rss_content = preg_replace('/<description.*?<\/description>/is', '', $rss_content);
    $rss_content = preg_replace('/<content:encoded.*?<\/content:encoded>/is', '', $rss_content);

    preg_match_all('/<item>(.*?)<\/item>/is', $rss_content, $matches);
    $new_items = array_slice($matches[0], 0, 5);
    $new_items_str = implode('', $new_items);
    $rss_content = preg_replace('/(<item>.*<\/item>)/is', $new_items_str, $rss_content);

    return $rss_content;
}

// 并行获取 RSS 内容
function parallel_get_rss_content($urls) {
    $mh = curl_multi_init();
    $handles = [];
    $responses = [];

    foreach ($urls as $i => $url) {
        $handles[$i] = curl_init($url);
        curl_setopt_array($handles[$i], [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_TIMEOUT => 10
        ]);
        curl_multi_add_handle($mh, $handles[$i]);
    }

    $running = null;
    do {
        curl_multi_exec($mh, $running);
    } while ($running > 0);

    foreach ($handles as $i => $handle) {
        $responses[$i] = curl_multi_getcontent($handle);
        curl_multi_remove_handle($mh, $handle);
    }

    curl_multi_close($mh);
    return $responses;
}

// 获取并缓存友情链接的最新文章数据
function get_cached_friend_link_rss_data($cache_update_interval, $cache_dir) {
    $links = get_cached_friend_links();
    $urls = [];
    $link_map = [];
    $redis = get_redis_instance();

    foreach ($links as $link) {
        if ($link->link_rss) {
            $domain = parse_url($link->link_url, PHP_URL_HOST);
            if (!$domain) {
                continue;
            }
            $cache_key = 'rss_'. $domain;
            $cache_file = $cache_dir. $domain. '.xml';

            $urls[] = $link->link_rss;
            $link_map[] = $link;
        }
    }

    if ($urls) {
        $responses = parallel_get_rss_content($urls);
        foreach ($responses as $i => $rss_content) {
            if ($rss_content!== '无法从提供 RSS 的 URL 获取 RSS 内容。') {
                $link = $link_map[$i];
                $domain = parse_url($link->link_url, PHP_URL_HOST);
                $cache_key = 'rss_'. $domain;
                $cache_file = $cache_dir. $domain. '.xml';
                $processed_rss_content = process_rss_content($rss_content);
                write_file($cache_file, $processed_rss_content);
                if ($redis) {
                    $redis->setex($cache_key, $cache_update_interval, $processed_rss_content);
                }
            }
        }
    }
}

// 执行缓存更新
get_cached_friend_link_rss_data(CACHE_UPDATE_INTERVAL, CACHE_DIR);    

2、friends.php的代码更改为:

温馨提示: 此处为隐藏内容,需要评论本文后才能查看.
评论后请刷新一次页面,但注意不要清除缓存,否则还需要再次评论!

3、宝塔后台建立计划任务如下:

优化朋友圈-似水流年
Comments | 8 条评论
  • 网友小宋

    Microsoft Edge 132 Microsoft Edge 132 Windows 10 Windows 10 1中国–河南–漯河 联通 ip address 125.44.*.*

    建议关掉,并无卵用

  • Jeffer.Z

    Google Chrome 107 Google Chrome 107 Android 15 Android 15 1中国–北京–北京 移动 ip address 117.129.*.*

    我也很震惊写入redis,目前大家通用都是写入一个静态文件json,然后读取页面渲染json的数据。但是我不太了解redis,所以对这种属于比较懵,redis意思是写入内存了吗。我是一种写入静态json渲染调用,一种是写入wp数据库使用wp自带的数据库缓存api。方法很多,效果好就OK啦。

  • 沉沦

    Google Chrome 134 Google Chrome 134 Mac OS X 10.15 Mac OS X 10.15 1中国 中国联通 ip address 2408:841d:59f0:a0a:*:*

    你这缓存到 redis 是我万万没想到的。友圈数据多了的话占内存啊,后台定时生成 json 文件存储吧,毕竟存储不像内存那么金贵。

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 1中国–河南 移动/数据上网公共出口 ip address 39.144.*.*

      我加了分批次处理,每次只处理10个网站,并且中间有一秒的间隔,下来网站还没有崩过。

  • obaby

    Google Chrome 132 Google Chrome 132 Mac OS X 10.15 Mac OS X 10.15 1中国 中国联通 ip address 2408:8418:d00:7555:*:*

    所有依赖于其他网站的内容,实时获取肯定是影响速度

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 1中国–河南–漯河 联通 ip address 182.126.*.*

      确实是这样。所以现在前端代码和后台获取分开了,后台定时获取并写入redis,随时为前台读取做好准备。

  • ymz316

    Firefox 128 Firefox 128 GNU/Linux GNU/Linux 1中国 中国电信 ip address 240e:384:dba2:5a00:*:*

    写的很详细,来学习代码了😁

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 1中国–河南–漯河 联通 ip address 182.126.*.*

      还得感谢你👍

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息