每个对象存储服务商都会提供工夫戳防盗链的反对,原理根本一样,本文以七牛云为例,服务端是用 Go 实现的 API。

生成签名的 url 的时候,也要将新生成的 url 保留到 redis 中,避免每次拜访都生成新的签名,即节约服务器资源,又会减少 CDN 流量。

签名代码:

// Sign 每一个图片生成 2 分钟有效期的签名//// imgPath 是图片门路,不是残缺链接。func Sign(imgPath string) (string, error) {    var (        // 七牛云设置的签名的 Key        key = "xxxxxxxxxx"            // 过期工夫        expire = time.Now().Unix() + 60*2    )    rawStr := fmt.Sprintf("%s/%s%x", key, imgPath, expire)    hash := md5.New()    hash.Write([]byte(rawStr))    sign := fmt.Sprintf("%x", hash.Sum(nil))    var newPath string    newPath = fmt.Sprintf("%s?sign=%s&t=%x", imgPath, sign, expire)      // 生成签名后放进 redis 中,过期工夫比签名过期工夫短 1 秒,下次再拜访时先从 redis 中查找签名过的链接    err := redis.CacheSignedURL(imgPath, newPath, 60*2-1)    if err != nil {        return "", err    }    return newPath, nil}

如果下次访问时没有从 redis 中获取到签名的 url ,再生成新的签名,伪码:

func GetSignedURL(url string) string {    cache := redis.GetCacheSignedURL(url)    if cache != "" {        return cache    }    return Sign(url)}

这样的益处就是在有效期内服务端返回的图片链接不会扭转,浏览器就可能缓存有效期内的图片。

当过有效期时,服务端返回新的签名链接,浏览器就会向七牛 CDN 收回新的申请,进行新一轮的有效期内缓存。

前端从响应 json 中拿到的签名链接渲染页面。


有效期内会在浏览器中缓存:

过了有效期就返回 403: