Wordpress更新提示Too Many Requests解决方案

2019年11月28日 804点热度 1人点赞 0条评论

不怕有问题, 就怕你不会解决问题.

周树人

发现问题

先解释一下Too Many Requests

在HTTP协议中,响应状态码 429 Too Many Requests 表示在一定的时间内用户发送了太多的请求,即超出了“频次限制”。

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/429

意思就是访问太频繁导致的, 但很多用户可能没有进行访问. 这可能与Wordpress验证机制有关吧, 猜测其他网站是按IP判断, wp官网可能用的IP段, 或是其他吧.

这就导致你可能没有访问过Wordpress的官网, 还是会出现这个423的错误, 安装插件或是更新等操作都会报错.

做出假设

既然服务器无法访问, 那么试试本地是否可以. 如果可以的话, 在本地下载好所需压缩包, 上传到服务器使其使用本地文件更新.

正常点击更新, 会有报错信息. 但是会有url信息, "正在从: https://downloads.wordpress.org/release/zh_CN/wordpress-x.x.zip下载", x.x就是更新的版本, 可以将连接复制一下直接下载下来.

提出方案

  • hook函数site_transient_update_core
  • 修改class-wp-upgrader.php文件

第一种是hook函数"site_transient_update_core", 使其在更新的时候返回一个其他连接进行下载更新. 目前网络中很多博主会提供这个方法, 并且放上自己的CDN连接, 切记不要轻易使用他人提供的连接进行更新.

第二种是直接改更新文件, 因为毕竟更新不是每天都需要的, 一两个月能用上一次, 所以改一次也不会浪费多少时间. 所以个人推荐这种, 毕竟所有操作透明都是自己操作.

实际实施

第一种很简单, 只需要在你的主题 functions.php(部分主题提供自定义代码文件所以并不是必须) 中添加以下代码.

add_filter('site_transient_update_core', function ($value) {
    foreach ($value->updates as &$update) {
        if ($update->locale == 'zh_CN') {
            $update->download = '#实际下载地址#';
            $update->packages->full = '#实际下载地址#';
        }
    }
    return $value;
}

简单解释一下, 判断如果语言是中文, 则将下载地址以及和包完整地址替换. 实际连接需要自己去搞定, 举例: 刚才不是下载完整包了么, 可以把这个包直接上传到你的网站根目录, 假设你的域名是 aabb.com, 更新的版本是5.5.1, 那么这个连接填写的就是"https://aabb.com/wordpress-5.5.1-zh_CN.zip", 后面的文件名不必纠结, 改什么都无所谓.

但是更新过后记得要把这段代码注释掉. 否则下次更新会一直循环, 检测到5.5.2个更新, 然后hook一直再给5.5.1的包.

第二种也不难, 还是刚才下载的完整包, 上传到服务器中, 位置随意. 找到wordpress安装目录"wp-admin/includes/class-wp-upgrader.php"。

/**
 * Download a package.
 *
 * @since 2.8.0
 * @since 5.5.0 Added the `$hook_extra` parameter.
 *
 * @param string $package          The URI of the package. If this is the full path to an
 *                                 existing local file, it will be returned untouched.
 * @param bool   $check_signatures Whether to validate file signatures. Default false.
 * @param array  $hook_extra       Extra arguments to pass to the filter hooks. Default empty array.
 * @return string|WP_Error The full path to the downloaded package file, or a WP_Error object.
 */
public function download_package( $package, $check_signatures = false, $hook_extra = array() ) {
    /**
     * Filters whether to return the package.
     *
     * @since 3.7.0
     * @since 5.5.0 Added the `$hook_extra` parameter.
     *
     * @param bool        $reply      Whether to bail without returning the package.
     *                                Default false.
     * @param string      $package    The package file name.
     * @param WP_Upgrader $this       The WP_Upgrader instance.
     * @param array       $hook_extra Extra arguments passed to hooked filters.
     */
    $reply = apply_filters( 'upgrader_pre_download', false, $package, $this, $hook_extra );
    if ( false !== $reply ) {
        return $reply;
    }

    if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { // Local file or remote?
        return $package; // Must be a local file.
    }

    if ( empty( $package ) ) {
        return new WP_Error( 'no_package', $this->strings['no_package'] );
    }

    $this->skin->feedback( 'downloading_package', $package );

    $download_file = download_url( $package, 300, $check_signatures );

    if ( is_wp_error( $download_file ) && ! $download_file->get_error_data( 'softfail-filename' ) ) {
        return new WP_Error( 'download_failed', $this->strings['download_failed'], $download_file->get_error_message() );
    }

    return $download_file;
}

找到这个 "download_package" 的函数. 在函数内的第一行添加以下内容.

$package = "/tmp/wordpress-5.5.zip"; 

后面路径就是你上传的路径, 你也可以在这里添加上第一步制作的连接. 然后再回到后台点击更新就可以了, 这种方法的好处就是, 你修改过的这个文件会在更新的时候覆盖掉, 防止出现hook更新之后忘了注释导致的一些问题.

方法二适用于更新主题和插件, 但是只有更新Wordpress会恢复文件, 如果更新插件或者主题, 改过记得改回去.

扩展

其实或多说少都有些许不方便, 毕竟涉及到代码. 在本地测试的时候因为从Wordpress后台直接安装或更新插件, 下载都很慢而且还容易因为网络问题下载出错.

所以就在本地测试的时候给Wordpress一个Proxy, 这样走其他一些线路会快一点, 生产环境如果有靠谱的也可以这么使用.

找到根目录下 wp-config.php, 添加以下代码

define('WP_PROXY_HOST', '127.0.0.1');
define('WP_PROXY_PORT', '10001');
define('WP_PROXY_USERNAME', 'username');
define('WP_PROXY_PASSWORD', 'password');
define('WP_PROXY_BYPASS_HOSTS', 'localhost, *.xx.com');
  • WP_PROXY_HOST: 代理主机的IP
  • WP_PROXY_PORT: 代理主机的端口
  • WP_PROXY_USERNAME: 代理认证所需要的用户名, 如果没有则留空
  • WP_PROXY_PASSWORD: 代理认证所需要的密码, 如果没有则留空
  • WP_PROXY_BYPASS_HOSTS: 排除名单, 名单内的网址网域不经过代理

出了代理, 其他办法都是千篇一律. 替换下载时候的连接而已, WP的大版本还是比较值的更新的, 毕竟会修复很多漏洞.

文章评论