内容纲要

Python+Golang的好处

  1. 上传的脚本很自然的想到用python,似乎没有更好的选择了,速度取决于服务器带宽
  2. 图床用golang,早就想试一下golang写服务端了,gogs的性能给我很深的印象,部署后居然常驻只用了3.966MB,以后服务端还会考虑其他语言么,不可能的。

为什么不用Picgo

大部分攻略用的都是Picgo,试了一下除了上传外还有其他小功能,几百兆的体积只是干几句python干的事似乎有点浪费,于是有了下面这个脚本,一共3kb,还不用常驻。

import os
import sys
import json
import requests
import mimetypes
import argparse
import time

APP_DESC = """
upload pictures automatically
"""
print(APP_DESC)
if len(sys.argv) == 1:
    sys.argv.append('--help')

parser = argparse.ArgumentParser()
parser.add_argument('-s', '--source', type=str, nargs='+', help="", required=True)
# parser.add_argument('-c', '--config', default="./config.json", help="读取配置文件", required=True)
args = parser.parse_args()

# 从参数中获取要上传的文件列表
img_list = args.source

# print(img_list)
Auth_Code = 'abcdef123456'
Image_Host = 'https://demo.com'

def uploadImage(filePath):
    fileName = os.path.basename(filePath)
    fileName = bytes(fileName, "utf-8").decode("unicode_escape")
    files = {'file': (fileName, open(filePath, 'rb'), mimetypes.guess_type(fileName)[0])}

    # Convert all non ASCII characters to UTF-8 escape sequence

    res = requests.post(url=Image_Host + '/upload',
                        files=files,
                        headers={'Authorization': Auth_Code, 'Uri': time.strftime("/%Y/%m/"), 'Image_Host': Image_Host})
    return json.loads(res.text)

def parse_response_url(json, img_path):
    # 从返回的json中解析字段
    if json['status_code'] != 200:
        print("{}\tweb端返回失败,可能是APIKey不对. status_code {} .".format(
            img_path, json['status_code'])
        )
    else:
        img_url = Image_Host + json["data"]["url"]
        print(img_url)

def uploadImageList(img_list):
    # 获得本地图片路径后,上传至图床并记录返回的json字段
    for img in img_list:
        # 先判断传过来的是本地路径还是远程图片地址
        if "http" == img[:4]:
            # 非本地图片的话可以考虑下载到本地再上传,但是没这个必要
            print(img)
            try:
                filename = img.split('/')[-1]
                r = requests.get(img, allow_redirects=True)
                filepath = r'~/srv/tmp/' + filename
                if os.path.isfile(filepath):
                    os.remove(filepath)
                open(filepath, 'wb').write(r.content)
                uploadImage(filepath)
                os.remove(filepath)
                print(img)
            except:
                print(img + "\t上传失败")
            continue
        else:
            try:
                res_json = uploadImage(img)
                parse_response_url(res_json, img)
            except:
                print(img + "\t上传失败")

uploadImageList(img_list)

为什么要自建图床?而不是使用本地相对路径的目录或者是github/gittee免费图床

本地相对路径限制太大,不好分享,也不方便文档的在组织。
各种免费图床,这个世界变化这么快,我宁可自己花钱靠得住一些,也没有容量大小限制等问题。
自建会不会麻烦,其实自用的简单图床只需要很少的代码比如下面:

package main

import (
    "io"
    "log"
    "net/http"
    "os"
)

var (
    // 文件 key
    uploadFileKey = "file"
    // 上传的图片保存根路径
    filePath = "/images/"
)

func main() {
    http.HandleFunc("/upload", uploadHandler)
    if err := http.ListenAndServe(":8081", nil); err != nil {
        log.Fatalf("error to start http server:%s", err.Error())
    }
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    // 接受文件
    file, header, err := r.FormFile(uploadFileKey)
    if err != nil {
        // ignore the error handler
    }
    log.Printf("selected file name is %s", header.Filename)
    authValue := r.Header.Get("Authorization")
    authCode := "abcdef123456"
    authCodeEnv, exists := os.LookupEnv("Authorization_Code")
    if exists {
        authCode = authCodeEnv
    }

    if authValue != authCode {
        log.Printf("auth fail")
        return
    }
    path := filePath + r.Header.Get("Uri")
    createFile(path)
    imgPath := path + header.Filename
    log.Printf("path is %s", path)

    // 将文件拷贝到指定路径下,或者其他文件操作
    dst, err := os.Create(imgPath)
    if err != nil {
        log.Fatalf("create file error :%s", err.Error())
        // ignore
    }
    _, err = io.Copy(dst, file)
    if err != nil {
        log.Fatalf("copy file error :%s", err.Error())
        // ignore
    }
    log.Printf("upload success")
    io.WriteString(w, "{\"status_code\": 200, \"data\": {\"url\": \""+(r.Header.Get("Image_Host")+r.Header.Get("Uri")+header.Filename)+"\"}}")
}

//调用os.MkdirAll递归创建文件夹
func createFile(filePath string) error {
    if !isExist(filePath) {
        err := os.MkdirAll(filePath, os.ModePerm)
        return err
    }
    return nil
}

// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
    _, err := os.Stat(path) //os.Stat获取文件信息
    if err != nil {
        if os.IsExist(err) {
            return true
        }
        return false
    }
    return true
}

上面的图床自用问题不大,如果多人多博客使用还需要完善以下几点

  1. 只有auth code鉴权,一个泄露就挂了
  2. 路径没有安全检测,如果泄露了auth code就有隐患
    服务端建议放在docker中。

发表评论

您的电子邮箱地址不会被公开。

浙ICP备14004285号-1