tinypng: 一个图片压缩工具
实现一个压缩工具
shell
### 压缩图片
curl https://api.tinify.com/shrink \
--user api:API_KEY \
--data-binary @01.png
### 可运行版本
curl https://api.tinify.com/shrink \
--user api:$TINYPNG_API_KEY \
--data-binary @01.png
rest client
POST https://api.tinify.com/shrink
Authorization: Basic b64(api:API_KEY)
Content-Type: application/octet-stream
< ./01.png
原理说明
Authorization Header: --user api:API_KEY 被转化为 Base64 编码的 Authorization 头。
其值是 api:API_KEY 的 Base64 编码结果 b64(api:API_KEY)。
Content-Type: 指定为 application/octet-stream,用于表示二进制数据。
Body: 使用 < ./01.png 指定文件上传内容。
认证原理
这是因为 HTTP 的基本身份验证(**Basic Authentication**)机制需要使用特定格式的 `Authorization` 头。
在 Basic Authentication 中:
1. **基本格式**:`Authorization: Basic <Base64(username:password)>`
- 需要将 `username:password` 拼接成一个字符串。
- 然后将拼接后的字符串用 Base64 编码。
2. **在你的例子中**:
- `username` 是 `user`。
- `password` 是 `PWD`。
- 拼接后为 `api:API_KEY`。
3. **Base64 编码的作用**:
- Base64 编码将这些凭据转换为一串 ASCII 字符,方便在 HTTP 头中传递,并避免特殊字符冲突。
- 你的 `Authorization` 头最终就是:
```
Authorization: Basic b64(user:pwd)
```
4. **工作原理**:
- 服务器接收到请求后,会将 `Authorization` 头解码,提取出 `username` 和 `password`,然后进行验证。
这是一种常见的身份验证方式,虽然易于实现,但由于 Base64 并非加密,仅是编码,所以需要通过 HTTPS 确保传输安全。
golang 实现
一个调用
api
的基本实现
package main
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"net/http"
"os"
)
func main() {
// API URL
url := "https://api.tinify.com/shrink"
// API Key
apiKey := "API_KEY"
// 文件路径
filePath := "01.png"
// 读取文件内容
fileData, err := os.ReadFile(filePath)
if err != nil {
fmt.Printf("Error reading file: %v\n", err)
return
}
// 创建 Basic Authentication 头
auth := "api:" + apiKey
authHeader := base64.StdEncoding.EncodeToString([]byte(auth))
// 创建 HTTP 请求
req, err := http.NewRequest("POST", url, bytes.NewReader(fileData))
if err != nil {
fmt.Printf("Error creating request: %v\n", err)
return
}
// 设置请求头
req.Header.Set("Authorization", "Basic "+authHeader)
req.Header.Set("Content-Type", "application/octet-stream")
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Error sending request: %v\n", err)
return
}
defer resp.Body.Close()
// 处理响应
if resp.StatusCode == http.StatusCreated {
fmt.Println("File compressed successfully!")
respData, _ := io.ReadAll(resp.Body)
fmt.Printf("Response: %s\n", string(respData))
} else {
respData, _ := io.ReadAll(resp.Body)
fmt.Printf("Failed to compress file. Status: %d, Response: %s\n", resp.StatusCode, string(respData))
}
}
POST url
curl https://api.tinify.com/shrink \
--user api:$TINYPNG_API_KEY \
--header "Content-Type: application/json" \
--data '{"source":{"url":"https://tinypng.com/images/panda-happy.png"}}'