加载中...
<cover></cover>

# 在 MWeb 中优雅地使用 GitHub + JsDelivr 图床

2021-03-06 技术向

本文最后更新于 天前，文中部分描述可能已经过时。

一直以来我都使用 iPad 作为主要的写作工具，得益于 Working Copy + MWeb 的神仙组合，我可以在 iPad 上非常便捷地完成博客文章的写作、推送，然后交给 GitHub Actions 完成静态博客自动构建（没错，我把慢吞吞的 Travis CI 换掉了）。

MWeb 作为一款非常优秀的 iOS/macOS 端 MarkDown 编辑器，其内置了强大的图片上传功能（也就是俗称的“图床”），可对接许多知名图床平台的 API 以及各大云计算平台的对象存储服务，写文章时可快速插入图片，省去了手动上传的过程。

最近我吃饱了撑的把博客的图片全部从腾讯云 COS 迁移到了 GitHub，并使用 JsDelivr CDN 进行全球加速，然而从上图中可知 MWeb 并未提供 GitHub 的图床接口，这可咋办呢？经过一番摸索，我找到了这个我自认为还不错的解决方案。

## 前言

首先需要声明的是，关于能否使用 GitHub + JsDelivr 作为图床（即是否有违 JsDelivr 的用户协议）目前仍存争议，我个人认为作为开发者合理使用是没有问题的，但坚决反对滥用行为（指作为个人网盘、作为下载站等行为）。

关于 MWeb 如何与 GitHub 联动的问题，其实并不是只有我一个人遇到了，在我写这篇文章之前就已经有人给出了解决方案，但是不能很好地满足我的需求，所以我就又写了这篇文章来记录。

## 实现思路

MWeb 虽然不支持直接添加 GitHub 图床，但是提供了「自定义图床」的选项，设置页面长这样：

根据这个页面可知，MWeb 通过 POST 请求把图片发送到自定义图床接口，图床接口返回图片上传的成功与否以及图片的相对路径或绝对路径。而 GitHub API 接口需要使用 PUT 方法上传文件，因此不能直接拿来用。

上文提到过的这篇文章给出了思路，即通过搭建一个类似于桥接器的服务，将 MWeb 发过来的 POST 请求转化为 PUT 请求再发送给 GitHub，就可以很好地解决这个问题。美中不足的是，该方案需要在本机上开机启动跑 Node.js 服务，而 iPad 根本就不可能做到，而且图片是直接传到根目录的，不符合我按日期分类的习惯，且返回给 MWeb 的图片链接是 GitHub 原始的绝对路径。

好在我又想到了 Vercel（貌似已经是第二次登场了23333），直接写个 Function 丢上去跑着就可以不用本地跑 Node.js 了，至于图片上传的目录可以通过修改代码实现，用 Moment.js 按日期分类图片，返回的路径也可以修改代码让其返回相对路径，最后由于服务是跑在远端向所有人公开的，所以需要设计一个鉴权流程防止仓库被别人恶意传图。

## 代码编写

由于整体框架和这篇文章差不多，我就直接 Fork 过来用了，省得造轮子。

（下文提到的代码都放在这个仓库）

首先要适配 Vercel，遂建立`/api`目录，把原本位于根目录下的`index.js`和`helper.js`挪动至此，修改`index.js`中的路由，同时不能再把配置写在文件里了，应当直接从环境变量中读取。

在`index.js`中：

    - const config = require('./config.json')
    - const url = config.url || '/upload'
    - var port = config.port || 8080
    + const url = process.env.URL || '/api'
    + var port = process.env.PORT || 8080

在`helper.js`中：

    - const config = require('./config.json')
    - const {repo, token} = config
    + const repo = process.env.REPO
    + const token = process.env.TOKEN

为了实现按日期分类，同时图片随机命名，需要修改`upload.js`中的相关代码。

    - let timestamp = moment().format('YYYYMMDDHHmmss')+'.jpg'
    - let imageUrl = 'https://api.github.com/repos/'+repo+'/contents/'+timestamp
    + let timestamp = moment().format('YYYY/MM/DD/')+Math.round(Math.random()*100000000)+'.jpg'
    + let imageUrl = 'https://api.github.com/repos/'+repo+'/contents/'+timestamp

同时需要使其返回相对路径而非 GitHub 原始绝对路径。

    - return imgUrl
    + return timestamp

最后加入鉴权机制，即校验 POST 请求中的 SECRET（通信密钥）字段是否与环境变量一致：

    if (fields.secret != process.env.SECRET) {
    	res.writeHead(200, {
    		"Content-Type": "text/json",
    		'Access-Control-Allow-Origin': '*'
    	}) res.write(JSON.stringify({
    		status: 'false',
    		info: 'Secret key invalid.'
    	})) res.end() return
    }

至此就已经基本完成改造了，推送部署到 Vercel 上，在 MWeb 中可以添加自定义图床进行测试。

点击「验证设置」，成功！

## 最终效果

## 参考链接

1. https://www.jianshu.com/p/3eaba5fcc65f

在 MWeb 中优雅地使用 GitHub + JsDelivr 图床
https://blog.hans362.cn/post/use-github-as-picbed-in-mweb/
本文作者
Hans362
最后更新
2021-03-06
许可协议
CC BY-NC-SA 4.0
转载或引用本文时请遵守许可协议，注明出处、不得用于商业用途！
喜欢这篇文章吗？考虑支持一下作者吧～
爱发电 支付宝