前言

自从去年底 jsdelivr 的备案被吊销后,其在我国大陆地区的速度相较于此前慢了非常多,幸亏有大佬无私分享了他反代的 jsd ,所以我的博客并没有受到太大的影响。

但是我尝试反代 jsd 的原因说起来也很无奈,一是因为重庆三大运营商对 jsd 有不同程度的 DNS 污染(2022年2月15日,重庆电信和移动恢复正常),另一个是大佬无私分享的反代链接有白名单机制,因此我在本地测试的时候往往得手动把链接换回成 jsd ,然后再代理一下才能测试效果。

jsd拨测部分情况

反代 jsd 的方案应该有很多,nginx 很轻松就能做到。但是想要低成本或者无成本反代,我做出了比较多的尝试,最终总结出两个我个人实践后可行的办法。

虚拟主机反代

虚拟主机相较于服务器而言成本更低,但是往往存在很多限制。我去年白嫖了蓝队云的免费不限带宽不限流量虚拟主机,详见《这可能是国内最好用的虚拟主机》,并且今年也成功续期了,不得不说蓝队云还是非常大方的。

但是我们今天的主角不是它,因为蓝队云的虚拟主机存在诸多限制,所以我此前尝试部署一个 php 网盘程序失败,今天尝试部署反代同样失败。所以今天的主角是来自灰狼云的免费虚拟主机

相较于蓝队云,灰狼云每次只能续期一个月,一月一续,如果要免除续期可以交一点点钱,或者购买付费虚拟主机(说实话,付费的价格也非常非常实惠)。

灰狼云虚拟主机

免费空间300MB,并发数100,流量15G/月,如果是为了反代个人使用的话,应该是完全够用的。这里省去领取和部署方法(直观并且确实无套路)。

关于反代的方法我在 github 上找到了好几个,但是实测下来有两个可用,其它的要么返回404,要么就是只能反代单页面(可能问题还是在于虚拟主机的限制)。

另外,如下两种虚拟主机反代的方法并未缓存对应文件到虚拟主机上,所以加载速度相对较慢。

第一种方法

①新建一个 php 文件,粘贴下面的代码,保存任意名称即可:

<?php
if(isset($_GET['url'])==false){die("请将参数填写完整,在当前路径后加上?url=反代的链接");}
$token=(string)rand(100,99999);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
curl_setopt($ch, CURLOPT_HEADER,false);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION ,1);
if(isset($_SERVER['HTTP_REFERER'])==true){curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER']);}
$data_down = curl_exec($ch);
if($data_down === FALSE){die("代理时发生错误");}
curl_close($ch);
file_put_contents($token, $data_down);
header('Content-Type: '.mime_content_type($token));
unlink($token);
echo $data_down;
?>

②将该文件上传到虚拟主机,然后访问你解析的域名+该文件名,在后面输入要反代的链接即可。

比如我下面这个链接:

https://w.hin.cool/proxy.php?url=https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.css

速度通常在几百毫秒以上,如果一次引入较多可能会拖慢速度,有更高速的需求可以尝试付费虚拟主机:

灰狼云jsd速度

第二种方法

如果你觉得上面的方式中,链接太过于冗长,想要类似于xxx.coml/npm/@fancyapps/ui/dist/fancybox.css这样的链接,在全局替换的时候也可以更简单,那么你可以尝试使用这个代码:

<?php
//代理的域名及使用的协议最后不用加/
$target_host="https://cdn.jsdelivr.net";
//处理代理的主机得到协议和主机名称
$protocal_host=parse_url($target_host);
//解决中文乱码
#header("Content-Type:text/html;charset=gb2312");
//获取浏览器的的Agent
$Agent = $_SERVER['HTTP_USER_AGENT'];
//以.分割域名字符串
$rootdomain=explode(".",$_SERVER["SERVER_NAME"]);
//获取数组的长度
$lenth=count($rootdomain);
//获取顶级域名
$top=".".$rootdomain[$lenth-1];
//获取主域名
$root=".".$rootdomain[$lenth-2];

//解析url参数
function get_request_params()
{
$url = $_SERVER["REQUEST_URI"];

$refer_url = parse_url($url);

$params = $refer_url['query'];

$arr = array();
if(!empty($params))
{
$paramsArr = explode('&',$params);

foreach($paramsArr as $k=>$v)
{
$a = explode('=',$v);
$arr[$a[0]] = $a[1];
}
}
return $arr;
}
//解析HTTP响应头
function parse_headers($headers)
{
//$head = array();
global $root,$top;
foreach( $headers as $k=>$v )
{
$t = explode( ':', $v, 2 );
if( isset( $t[1] ) )
{
//$head[ trim($t[0]) ] = trim( $t[1] );
if(strcasecmp('Set-Cookie',trim($t[0]))==0)
{
//处理COOkie的domain关键字
$targetcookie=trim( $t[1] ).";";
$res_cookie=preg_replace("/domain=.*?;/","domain=".$root.$top.";",$targetcookie);
$res_cookie=substr($res_cookie,0,strlen($res_cookie)-1);
header("Set-Cookie: ".$res_cookie);
}
elseif(strcasecmp('Content-Type',trim($t[0]))==0)
{
header("Content-Type: ".trim( $t[1] ));
}
elseif(strcasecmp('Location',trim( $t[0] ))==0)
{
$relocation=str_replace($protocal_host['host'],$_SERVER["SERVER_NAME"],trim( $t[1] ));
header("Location: ".$relocation);
}
elseif(strcasecmp('cache-control',trim( $t[0] ))==0)

header("cache-control: ".trim( $t[1] ));

else
continue;
}
// else
// {
// $head[] = $v;
// if( preg_match( "#HTTP/[0-9\.]+\s+([0-9]+)#",$v, $out ) )
// $head['reponse_code'] = intval($out[1]);
// }
}
return;// $head;
}
//关系数组转换成字符串,每个键值对中间用=连接,以; 分割
function array_to_str($array)
{
$string="";
if (is_array($array))
{
foreach ($array as $key => $value)
{
if(!empty($string))
$string.="; ".$key."=".$value;
else
$string.=$key."=".$value;
}
} else
{
$string = $array;
}
return $string;
}
//debug to console
function debug_to_console($data) {
if(is_array($data) || is_object($data))
{
echo("<script>console.log('PHP: ".json_encode($data)."');</script>");
} else {
echo("<script>console.log('PHP: ".$data."');</script>");
}
}
//组装HTTP请求头
$opts="";
if($_SERVER['REQUEST_METHOD']=='POST')
{
$postdata=file_get_contents("php://input");
$opts = array(
'http'=>array(
'method'=>$_SERVER['REQUEST_METHOD'],
'content'=>$postdata,
'header'=>"Accept-language: zh-CN\r\n" . //可以使用客户端浏览器的$_SERVER['HTTP_ACCEPT_LANGUAGE']
"user-agent: '$Agent'"."\r\n".
"Cookie: ".array_to_str($_COOKIE)."\r\n".
//"Accept-Encoding: gzip, deflate, sdch\r\n".
"Content-Type: ".$_SERVER['CONTENT_TYPE']

)
);

}
else
{
$opts = array(
'http'=>array(
'method'=>$_SERVER['REQUEST_METHOD'],
'header'=>"Accept-language: zh-CN\r\n" .
"user-agent: '$Agent'"."\r\n".
//"Accept-Encoding: gzip, deflate, sdch\r\n".
"Cookie: ".array_to_str($_COOKIE)
)
);

}
//
$context = stream_context_create($opts);
//发送请求
$new_request_uri = "";
$path_script = pathinfo($_SERVER["PHP_SELF"]);
//
if ($path_script['dirname']!="/") {
$new_request_uri = substr_replace($_SERVER["REQUEST_URI"],"",strpos($_SERVER["REQUEST_URI"],$path_script['dirname']),strlen($path_script['dirname']));
} else {
$new_request_uri = $_SERVER["REQUEST_URI"];
}
$homepage = file_get_contents($protocal_host['scheme']."://".$protocal_host['host'].$new_request_uri,false,$context);
//处理file_get_contents返回的响应求头
parse_headers($http_response_header);
//替换域名并输出网页
$homepage=str_replace($protocal_host['host'],$_SERVER["SERVER_NAME"],$homepage);
//输出网页内容
echo $homepage;
?>

并且需要额外配置伪静态,apache 的示例如下:

RewriteEngine on
RewriteBase /
RewriteCond $1 ^(index\.php)?$ [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} ^index\.php?$
RewriteRule ^(.*)$ - [S=1]
RewriteRule . /index.php [L]

CDN 反代

在折腾了多个 PHP 反代之后,我想,难道就没有更简便的方法了吗,或者速度更快的?联想到 jsd 本质上就是一个 CDN ,没有缓存的内容都会回源去取,所以我想到了其它 CDN !

关于 CDN 我此前也写过一篇《国内免费CDN和云存储测评分享》,除了又拍云我不建议使用外,其它的看你自己的喜好。如果你没有备案域名,那你或许也可以尝试一下 cloudflare (当然仅在你无法直接访问jsd的时候,因为速度不一定比 jsd 本身快)

方法也非常简单,新建一个 CDN ,域名输入你自己要解析的域名,源站域名和回源 Host 都填写cdn.jsdelivr.net,回源协议选择“协议跟随”,为了避免 CDN 节点所在的运营商也屏蔽了 jsd ,热备源站或许可以试试套娃。

此外,记得开启回源跟随301、302。

cdn反代配置

那么反代后的链接应该就是:

https://xxx.com/npm/@fancyapps/ui/dist/fancybox.css

速度大概就是这个样子,第一次访问因为要回源所以比较慢,CDN 节点有缓存之后速度会快很多:

cdn反代速度

此外就是配置防盗链和设置流量阈值什么的了,请参考我曾经被刷流量的教训。

经测试,腾讯云 CDN 同样可以!

群里的疑问

腾讯云cdn反代测试

总结

昨天听群里有人说北京也出现了 jsd 无法访问的情况,不知道未来这个现象会不会扩大。自己反代 jsd 建议在无法访问或者访问速度奇慢的情况下使用。以上两种方法各有优劣,大家可以根据自己的需求来选择。

最后还是要提醒一下各位,遵纪守法,也要懂得保护自己,不要为任何违法犯罪的行为提供机会和帮助。