
前言:PicGo 的挣扎与 R2 的“门槛”
最近在搭建自己的技术博客(使用 Typecho),图床是绕不开的话题。市面上大多数教程都推荐使用 PicGo 搭配各种云服务(如 GitHub、七牛云、腾讯云 COS、阿里云 OSS 等)。起初,我也尝试了 PicGo。
然而,一系列问题接踵而至:
- NPM 环境报错:尝试安装 PicGo 插件时,控制台不断弹出
Error: spawn npm ENOENT和NPM is not installed的错误。作为 C++/Go 开发者,我实在不想为了一个图床工具专门去配置一套 Node.js 环境。 - Cloudflare R2 的“洗礼”:转向 Cloudflare R2,它那免费的 10GB 存储和免费流量费简直是为个人博客量身定制。然而,R2 强制要求绑定付款方式,甚至在我的网络环境下触发了支付“人脸验证”——这无疑给硬核技术者设立了一道不必要的门槛。
面对这些“非代码”问题,我决定回归本源:用 Go 语言自己写一个!
解决方案:Go 语言自制 GitHub 图床工具
我的需求很简单:
- 能将本地图片上传到云端。
- 上传后自动复制 Markdown 格式的链接。
- 部署和使用必须足够简单,最好是一个可执行文件。
- 免费,且加载速度快。
最终,我选择了 GitHub 仓库 + jsDelivr CDN 的组合,并用 Go 语言编写了一个命令行工具。
1. GitHub 仓库准备
首先,在 GitHub 上创建一个公共仓库,例如 osluck/blog-img。这个仓库将用于存放你的所有博客图片。
接着,生成一个 Personal Access Token (PAT),用于 Go 脚本调用 GitHub API。
- 进入 GitHub Settings -> Developer settings -> Personal access tokens -> Tokens (classic)。
- 点击 “Generate new token (classic)”。
- Note 填写
blog-img-uploader,Expiration 建议选择 “No expiration”。 - Scopes (权限) 只需勾选
repo。 - 生成后,务必复制并保存生成的
ghp_xxxx字符串,这将是你的 Go 脚本中token的值。
2. Go 语言核心代码
这个 Go 脚本会读取本地图片文件,将其 Base64 编码,然后通过 GitHub API 推送到你的 blog-img 仓库的 uploads/ 目录下。上传成功后,它会自动构造一个 jsd.cdn.zzko.cn 加速链接的 Markdown 格式,并复制到剪贴板。
Go
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"time"
"github.com/atotto/clipboard" // 用于复制到剪贴板
)
func main() {
// 确保程序接收到图片路径参数
if len(os.Args) < 2 {
fmt.Println("用法:请将图片文件拖拽到此程序上")
time.Sleep(3 * time.Second) // 窗口停留几秒,方便查看提示
return
}
// --- 请修改以下配置为你自己的 GitHub 信息 ---
const (
owner = " " // 你的 GitHub 用户名
repo = " " // 存放图片的仓库名
token = "你的_GITHUB_TOKEN" // 刚才生成的 GHP 开头的 Token
)
filePath := os.Args[1] // 获取拖拽进来的图片文件路径
// 读取图片内容
fileData, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Printf("错误:无法读取文件 %s: %v\n", filePath, err)
time.Sleep(3 * time.Second)
return
}
// Base64 编码图片内容,以便通过 GitHub API 上传
base64Content := base64.StdEncoding.EncodeToString(fileData)
// 构建 GitHub API 上传路径:uploads/时间戳.扩展名
// 这样可以避免文件名冲突,并按上传时间归类
fileName := fmt.Sprintf("%d%s", time.Now().Unix(), filepath.Ext(filePath))
apiUrl := fmt.Sprintf("https://api.github.com/repos/%s/%s/contents/uploads/%s", owner, repo, fileName)
// 构造 PUT 请求的 JSON Payload
payload := map[string]string{
"message": "upload by go-cli-uploader", // commit 信息
"content": base64Content,
}
jsonData, err := json.Marshal(payload)
if err != nil {
fmt.Printf("错误:JSON 序列化失败: %v\n", err)
time.Sleep(3 * time.Second)
return
}
// 发送 HTTP PUT 请求到 GitHub API
req, err := http.NewRequest("PUT", apiUrl, bytes.NewBuffer(jsonData))
if err != nil {
fmt.Printf("错误:创建请求失败: %v\n", err)
time.Sleep(3 * time.Second)
return
}
// 设置 Authorization header,使用 Token 进行身份验证
req.Header.Set("Authorization", "token "+token)
req.Header.Set("Content-Type", "application/json") // 必须指定内容类型
client := &http.Client{}
resp, err := client.Do(req) // 执行请求
if err != nil {
fmt.Printf("错误:HTTP 请求失败: %v\n", err)
time.Sleep(3 * time.Second)
return
}
defer resp.Body.Close() // 确保关闭响应体
// 检查 GitHub API 返回的状态码
if resp.StatusCode == 201 { // 201 Created 表示成功
//备用链接1 https://jsd.cdn.zzko.cn/gh
//备用链接2 https://jsd.onmicrosoft.cn/gh
//全球加速3 https://cdn.jsdelivr.net/gh
finalURL := fmt.Sprintf("https://jsd.onmicrosoft.cn/gh/%s/%s/uploads/%s", owner, repo, fileName)
markdown := fmt.Sprintf("", finalURL)
//将Markdown 链接复制到剪贴板
err = clipboard.WriteAll(markdown)
if err != nil {
fmt.Printf("提示:链接已生成但复制到剪贴板失败:%v\n", err)
}
fmt.Printf("✅ 图片上传成功!Markdown 链接已复制到剪贴板。\n")
fmt.Printf("链接:%s\n", finalURL)
} else {
// 上传失败,打印错误信息
respBody, _ := ioutil.ReadAll(resp.Body) // 读取错误响应体
fmt.Printf("❌ 图片上传失败!HTTP 状态码: %d\n", resp.StatusCode)
fmt.Printf("GitHub API 响应: %s\n", string(respBody))
}
time.Sleep(5 * time.Second) // 延长窗口停留时间,方便调试
}
3. 编译与部署
- 初始化 Go Module:在
main.go所在目录打开终端,执行go mod init github.com/yuyetufu/blog-uploader(模块名可自定义)。 - 安装依赖:
go mod tidy。 编译程序:
go build -ldflags="-s -w -H=windowsgui" -o uploader.exe。-ldflags="-s -w":减小可执行文件体积。-H=windowsgui":生成无命令行窗口的 GUI 程序(Windows 特有)。
集成到右键菜单:
- 按下
Win + R键,输入shell:sendto回车。 - 将编译好的
uploader.exe的快捷方式拖入弹出的文件夹中。
- 按下
4. 使用方式
现在,当你需要上传一张图片到博客时:
- 在文件管理器中,找到你的图片。
- 右键点击图片 -> 选择 “发送到” -> 点击 “uploader.exe”。
- 稍等片刻(取决于你的网络速度),程序将在后台完成上传。
- 打开你的博客编辑器,直接
Ctrl + V粘贴,Markdown 格式的图片链接便会显示出来。
结语
一个轻量、高效、完全由自己掌控的图片上传方案。“自己动手,丰衣足食”的优雅,就是开发者而言,无疑是最好的体验。