网站调试

作者:Dave Taylor

我知道,我现在正在写一系列关于如何在命令行中使用 ImageMagick 的专栏文章,但是当其他事情出现时,嗯,我想你们很多人都以某种方式参与服务器或系统的管理,所以你们都理解救火。

当然,这意味着你们也都理解负反馈循环,它是系统管理和 IT 管理的内在组成部分。我的意思是,人们不会打电话给你,CEO 也不会发备忘录说:“系统整天运行良好,打印机甚至也打印了。谢谢!”

不,只有当事情出错时你才会听到消息,而这种忽视好的方面,不得不处理坏的方面(当它出现时)的倾向,不仅是企业 IT 的一个特点,如果你运行自己的系统,这也是同样真实的——这就是这个月它突然出现并困扰我的方式。

这一切都始于十年前我的 Ask Dave Taylor 网站。你可能已经遇到过它,因为它已经存在十多年了,并且在此期间为数千万访客提供了有用的教程信息。

十年前,选择 Movable Type 作为我的博客平台是完全合理的,并且是原始的、未完成的 WordPress 平台及其永无止境的黑客和问题的明智替代方案。然而,正如每个企业 IT 人员都知道的那样,有时你会锁定错误的平台,然后被困住,迁移所需的工作量每月都在增加,但什么都没有发生。

因此,为了网站的十周年纪念,是时候了。我不得不咬紧牙关,将所有 3,800 篇文章和 56,000 条评论从 Movable Type 迁移到 WordPress,因为是的,WordPress 赢了,并且显然是当今内容管理系统的行业标准。

这项任务令人生畏,不仅仅是因为导入的规模(它需要咨询团队重写标准导入工具以处理如此多的文章和评论),还因为命名方案发生了变化。在 Movable Type 上,我总是将其设置为将文章的名称转换为像这样的 URL

名称:Pinterest 入门

URL:/getting_started_with_pinterest.html

这很简单直接,但是在 WordPress 上,URL 使用破折号而不是下划线,更重要的是,它们不以 .html 结尾,因为它们是根据需要动态生成的。这意味着新的 WordPress 站点的默认 URL 看起来像这样

新 URL:/getting-started-with-pinterest/

URL 可以在导入时进行映射,以便默认的破折号变为下划线,但后缀是一个问题,并且在导入后,有 3,800 个 URL 损坏了,因为每个指向 xx_xx.html 的链接都失败了。

啊! 301 重定向! 是的,但是数千个重定向会减慢每个人的服务器速度,因此重写规则更好。在 Apache 中,你可以指定“如果你看到 xx_xx.html 形式的 URL,将其重写为 'xx_xx' 并重试”,这是一个非常方便的功能。

但是生活从来没有那么容易,因为虽然这种重写适用于旧站点上 95% 的 URL,但有些 URL 最终会得到不同的 URL,因为我在某个地方修改了一些东西。是的,总会有一些事情。

例如,旧站点 URL /schedule_facebook_photo_upload_fan_page.html 现在在服务器上的 URL 是 /schedule-a-facebook-photo-upload-to-my-fan-page/。

这很有帮助,对吧?(叹气。)

这些都可以通过 301 重定向来处理,但问题是,在旧站点上近 4,000 个文章 URL 中,哪些实际上没有成功地通过重写规则(.html 到尾部斜杠)映射到新服务器上的页面?

终于要写脚本了

为了识别这些重写失败,我必须创建一个脚本——而且要快。毕竟,虽然内部链接可能仍然有效,但来自 Popular Science华尔街日报Wired 和其他地方的数千个外部链接已损坏。哎呀——一点也不好。

我从命令行开始,使用一个我知道会失败的链接。这是当我使用 curl 获取新站点上的错误 URL 时发生的情况


$ curl
http://www.askdavetaylor.com/
↪schedule-facebook-photo-upload-to-my-fan-page.html
| head -5

% Total  % Received % Xferd  Average Speed  Time  Time  Time Current
                             Dload  Upload  Total Spent Left Speed
0     0  0    0     0     0      0     0 --:--:-- --:--:-- --:--:--
0<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<h3>Nothing found for
Schedule-A-Facebook-Photo-Upload-To-My-Fan-Page</h3>
100 31806   0 31806  0   0  110k  0 --:--:-- --:--:-- --:--:-- 110k
curl: (23) Failed writing body (0 != 754)

哎呀,这真是太乱了,这并不奇怪,因为我忘记在调用 curl 时添加 -silent 标志。

尽管如此,这里显示的内容足以提供一个重要的线索。这是一个 404 错误页面,正如预期的那样,<h3> 表明了这一点


<h3>Nothing found for ...

所以这是一个容易搜索的模式


curl -silent URL | grep '<h3>Nothing found for'

这招奏效了。如果输出是非零的,则链接失败并生成了 404 错误,但如果链接有效,它将是文章的正确标题,并且会出现“Nothing found for”字样。

这已经是脚本所需的大部分逻辑了。唯一剩下的步骤是模拟重写规则,以便所有有效的链接都不会被标记为问题。很简单


newname="$(echo $name | sed 's/\.html/\//')"

实际上,这是一个我在脚本中使用的超级常见的序列,使用子 shell 调用 $( ) 回显变量的当前值,只是为了将其通过 sed 替换,在本例中将 .html 替换为尾部斜杠(需要用前导反斜杠转义,因此模式很复杂)。

将其包装在一个 for 循环中,该循环遍历所有可能的 *.html 文件,这就是它的样子


for name in *.html ; do
  newname="$(echo $name | sed 's/\.html/\//')"
  test=$($curl $base/$newname | grep "$pattern")
  if [ -n "$test" ]
  then
    echo "* URL $base/$name fails to resolve."
  fi
done

但这很无聊,因为当我在做这件事的时候,我想知道测试了多少个 URL 以及遇到了多少个错误。我的意思是,为什么不呢,对吧?量化 = 好。

事实证明,这很容易添加,只需添加两个新变量(这两个变量都需要在脚本顶部设置为零)


for name in *.html ; do
  newname="$(echo $name | sed 's/\.html/\//')"
  test=$($curl $base/$newname | grep "$pattern")
  if [ -n "$test" ] ; then
    echo "* URL $base/$name fails to resolve."
    error=$(( $error + 1 ))
  fi
  count=$(( $count + 1 ))
done

然后在脚本的最后,在报告所有特定错误之后,进行状态更新


echo ""; echo "Checked $count links, found $error problems."

太棒了。让我们运行它


$ bad-links.sh | tail -5

* URL http://www.askdavetaylor.com/whats_a_fast_way_to_add_a_
↪store_and_shopping_cart_to_my_site.html fails to resolve.

* URL http://www.askdavetaylor.com/whats_amazons_simple_
↪storage_solution_s3.html fails to resolve.

* URL http://www.askdavetaylor.com/whats_my_yahoo_
↪account_password_1.html fails to resolve.

* URL http://www.askdavetaylor.com/youtube_video_
↪missing_hd_resolution.html fails to resolve.

Checked 3658 links, found 98 problems.

呼。现在我知道了特殊情况,可以应用自定义 301 重定向来修复它们。当你读到这篇文章时,网站上一切都会好起来的(或者应该会更好)。

Dave Taylor 长期以来一直在 UNIX 和 Linux 系统上编写 shell 脚本。他是 Learning Unix for Mac OS XWicked Cool Shell Scripts 的作者。你可以在 Twitter 上找到他 @DaveTaylor,你也可以通过他的技术问答网站联系他:Ask Dave Taylor

加载 Disqus 评论