0%

Hexo 生成 RESTful API 供外部抓取

缘起

因工作上的业务需求,希望从公司主站来抓取公司博客站点上的文章,并展示在公司主站的二级页面上。我尝试让 Hexo 通过 RESTful API 来输出文章列表和各篇文章的 JSON,然后用 JSONP 的方式实现跨域抓取。

过程

业务逻辑

简单整理了一下思路,实现逻辑大致是这样:

Hexo 的 JSON 输出

安装 RESTful 插件

参考 官方说明

安装:npm install hexo-generator-restful --save

配置:nano hexo/_config.yml,在文件最后添加如下配置信息:

restful:
# site 可配置为数组选择性生成某些属性
# site: ['title', 'subtitle', 'description', 'author', 'since', email', 'favicon', 'avatar']
site: true # hexo.config mix theme.config
posts_size: 10 # 文章列表分页,0 表示不分页
posts_props: # 文章列表项的需要生成的属性
title: true
slug: true
date: true
updated: true
comments: true
path: true
excerpt: false
cover: true # 封面图,取文章第一张图片
content: false
keywords: false
categories: true
tags: true
categories: true # 分类数据
use_category_slug: false # Use slug for filename of category data
tags: true # 标签数据
use_tag_slug: false # Use slug for filename of tag data
post: true # 文章数据
pages: false # 额外的 Hexo 页面数据, 如 About

部署至服务器后,Hexo 站点就有了 API 功能。

请求 API

依照不同的需求,可以请求对应的 API 来获取 JSON:

GET /api/site.json #获取站点信息
GET /api/posts.json #获取文章列表,包括文章路径
GET /api/articles/<文章路径名称>.json #根据具体文章路径获取文章内容

通过在浏览器中访问 <域名>/api/articles/<文章路径名称>.json 来查看 JSON 输出。

JSONP 跨域请求

服务端

我简单写了一个 PHP 文件来处理客户端的 JSONP 请求:

<?php
header("Content-Type: text/javascript"); //使文件输出为 JS 格式而非 HTML
$q = $_GET['q']; //获取客户端所请求的文件地址
$r = '../<Hexo 站点路径>/' . $q; //拼接上内部文件路径
$callback = $_GET['callback'];
echo $callback . "("; //拼接 JSONP 回调格式
include($r); //输出客户端所请求的 JSON 文件
echo ")";
exit;
?>

部署在服务端的 Hexo 站点是纯静态的,并且每次部署会被重置。因此,我另建了一个目录用于放置 PHP 这类动态文件:

$ ls
$ <Hexo 目录> <PHP 目录>

服务器安装好 PHP7.0 后,编辑原本 Hexo 站点的 Nginx 配置文件,加入针对 PHP 文件的反向代理。文件片段:

server {
...
location ~ \.php$ {
root <PHP 目录>;
try_files $uri =404;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
...
}

客户端

使用 JQuery 来从客户端发起 AJAX 的 GET 请求,HTML 代码片段:

<html>
...
<body>
<div id="result"></div>
<script src="<JQuery 引用地址>" /></script>
<script>
window.addEventListener('load', function () {
var url = "api/articles/<文章路径名称>.json"; //目标博客文章 JSON 文件的相对路径
url = encodeURIComponent(url); //对 URL 中的斜杠等符号进行转义
$.ajax({
type: "get",
url: "<站点地址>/api.php?q="+url,
dataType: "jsonp",
jsonp: "callback",
jsonpCallback:"success_jsonpCallback",
success: function(data){
$('#result').append(data.title); //测试输出 JSON 中的文章标题
$('#result').append(data.content); //测试输出 JSON 中的文章正文
}
});
});
</script>
</body>
</html>

查看测试网页中的输出。

结语

以上只是一个简单的测试,证明我的解决方案在业务逻辑上能够跑通。接下来是一些客户端层面的逻辑处理,思路是通过 JSONP 请求 api/posts.json 来获取文章列表,挑出最新的几篇文章的 JSON 路径,然后通过 JSONP 请求 api/articles/<文章路径名称>.json 来获取文章内容。

EOF