MENU

利用CDN突破防盗链搭建高速图片源站

May 25, 2019 • Read: 95601 • 技术杂谈

1. 前言

作为一名90(其实是95)后,QQ空间相信不少人肯定都接触过 ;初高中时期要是三天不发一条状态就不舒服,哈哈。不过进入大学之后就很少玩了,发动态的频率逐渐降低,一个月、半年、一年到现在基本不发,更多的是关注好友们的动态;好吧,废话有点多,前面就当叙旧。

94ee688a5de0b4eb439fabd15d0a17a5.jpg

回到正题,某次发现一些00后QQ空间里面出现了一些有趣的事情,喜欢收集各种头像,同时号称百万级别,看了一下实际数量,的确有:joy:;大概是下面这个样子...
百万头像.png

哇...,这么多漂亮的小姐姐;于是我决定利用爬虫把所有图片全部爬下来,花了半天时间写了个Py爬虫把图片URL源地址全部保存了下来,爬了四五个QQ号;文件全部打包之后也有两百多M;独乐乐不如众乐乐,我决定利用这些文件做一个随机头像API(莫名API),已经完工!~~
压缩包.png

Ps:如果需要Py爬虫和这个文件压缩包,可评论留下邮箱;爬虫写的很草率(乱、菜)...

2. 面临问题

等我认为自己已经完成部署之后,某次自己调用,却发现QQ空间针对每个相册图片都开启了防盗链,如果放在网页中调用,就会出现下面这个东西...
QQ空间防盗链.png
这让我很尴尬,因为之前测试是没问题的,后来测试发现,前面没问题是因为浏览器缓存。

好吧,问题来了,该怎样才能实现,突破QQ空间相册图片的防盗链限制。

3. 解决方法

百度了一波,很多人也面临同样问题,也有部分解决方法,但大部分都是在客户端进行,比如伪造请求报文;也有反向代理的,但我这里情况有点特殊;首先一点,因为我是在制作API,伪造请求头治标不治本,没啥用;反向代理不错,但考虑到API肯定多人调用,宽带和速度就是一个问题;想了许久,琢磨出了一个奇淫技巧,足以解决防盗链,宽带速度问题,哈哈!~~

反向代理 + 服务器缓存 + CDN


4. 实战操作

这里主要说下我的API是如何运行,具体到某个应用场景的话变通一下应该也没什么问题。
首先看下QQ空间相册图片的真实源地址

http://b327.photo.store.qq.com/psb?/V12Ma7dD3W12BL/EUvBdz3a9vtoDMDvlM.QmGN*rXlQ8.tL8Afs4Z8EzUA!/b/dIf.78KYCAAA&ek=1&kp=1&pt=0&bo=*gGoAgAAAAAKJ14!&tl=1&vuin=1538236552&tm=1557151200#sce=14-1-1&rf=v1_ht5_qz_3.4.0_001_idc_b-4-0

去掉没用的参数

http://b32.photo.store.qq.com/psb?/V12Ma7dD3W12BL/EUvBdz3a9vtoDMDvlM.QmGN*rXlQ8.tL8Afs4Z8EzUA!/b/dIf.78KYCAAA

对这个URL分析一下,其实QQ空间也是使用了类似CDN部署,前面的主机域名b32.photo.store.qq.com换成http://b56.photo.store.qq.com进行请求访问也是同一张图片.
那主要关键参数其实就是/psb?/V12Ma7dD3W12BL/EUvBdz3a9vtoDMDvlM.QmGN*rXlQ8.tL8Afs4Z8EzUA!/b/dIf.78KYCAAA,相当于如果调用我的API接口,返回这个参数即可,但是如果真的这样返回,没人看得懂什么意思;所以还是需要返回一个URL地址,而这个URL地址是已部署的反向代理站点,同时需要代入关键参数,这样代理站点才知道需要的请求的是哪张图片;没懂?没关系,看我的API接口。


API地址:https://api.qzone.work/rand.headpic
返回参数:

{
    "code": 10000,
    "msg": "success",
    "data": {
        "url": "https://qn.cdn.vizan.cc/api/randheadpic?/sa14V102mtFb1cnm7r320d14cd65fc315f05cba5b7d8ef7f804914V11AkucI4bCyox/h5xBGc.suATcVJd6eeVnZBbREEZ27VKggKRBIUblIVQ!/b/dDYBAAAAAAAA"
    },
    "time": 0.00452
}

其中的URL地址https://qn.cdn.vizan.cc/api/randheadpic?/sa14V102mtFb1cnm7r320d14cd65fc315f05cba5b7d8ef7f804914V11AkucI4bCyox/h5xBGc.suATcVJd6eeVnZBbREEZ27VKggKRBIUblIVQ!/b/dDYBAAAAAAAA即代理请求地址,其中sa14V102mtFb1cnm7r320d14cd65fc315f05cba5b7d8ef7f804914V11AkucI4bCyox/h5xBGc.suATcVJd6eeVnZBbREEZ27VKggKRBIUblIVQ!/b/dDYBAAAAAAAA为关键参数。


再来看看代理站点如何运行,看代码:

<?php
set_time_limit(0);
error_reporting(0);
header('Access-Control-Allow-Origin: *');
header("Content-type:image/jpeg;charset=UTF-8;");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS,PATCH');

$query = $_SERVER['QUERY_STRING'];
$filename = __dir__.'/headPIC/'.md5($query).'.jpg';

if(file_exists($filename)){ //直接读取本地文件
    $imgbin = file_get_contents($filename);
}else{
    // 拉取远程数据
    $params['scheme']='https';
    $params['host']='photo.store.qq.com';
    $params['path']='/psb';
    $params['query']= $query;
    $url = buildUrl($params);
    $imgbin = file_get_contents($url);
    $str = mb_substr($imgbin,0,8);
    
    // 判断返回是否 是相册图片
    if(strpos($str,'JFIF') !== false)
        // 本地缓存一份
        @file_put_contents($filename,$imgbin);
}

exit($imgbin);

function buildUrl($params) {
    return (isset($params['scheme']) ? $params['scheme'] . '://' : NULL) . (isset($params['user']) ? $params['user'] . (isset($params['pass']) ? ':' . $params['pass'] : NULL) . '@' : NULL) . (isset($params['host']) ? $params['host'] : NULL) . (isset($params['port']) ? ':' . $params['port'] : NULL) . (isset($params['path']) ? $params['path'] : NULL) . (isset($params['query']) ? '?' . $params['query'] : NULL) . (isset($params['fragment']) ? '#' . $params['fragment'] : NULL);
}

代码解释:首先允许跨域调用,判断本地是否有缓存文件,如果没有的话构建QQ空间真实相册图片地址再获取一份,保存到本地,最后输出返回图片文件。


OK,流程比较简单,代码可以再优化健壮一点,这里就不讲了,如果请求图片没有缓存,那请求时间可能就要多一点。
其实到这里,基本上整套流程都已经结束,但是考虑到服务器宽带速率问题(我的1M小水管),所以又引入了CDN提高访问速度,相当于二次缓存,做到如题目一样(高速图片源站)。

每家云服务商的CDN配置均有不同,如果你用腾讯云请参考我的另外一篇文章(博客全站启用腾讯CDN并部署SSL),我这里使用的是七牛CDN,实名账户有免费额度。

关键一点在于CDN缓存的配置,把每次访问的图片交给CDN服务器缓存起来,减少对源站的请求,这是我的七牛配置图。
七牛CDN配置.png

每个图片的关键参数肯定是一一对应的,所以缓存时间调到高一点也无大碍,CDN配置推荐对宽带上线和流量做一定限制,防君子不防小人。

5. 总结

之前从未做过此类部署,第一次这样玩,感觉挺有意思的,做一次记录;这种实践,相当于把所有已知的、了解的知识或“功底”糅杂在一起的应用。

Last Modified: June 13, 2020