先看成品:
我是个抖音重度使用者,平时看到比较有意思或者让人思考的短视频,我总喜欢把他下载到手机相册中,然后分享给朋友。避免视频失效,而且不消耗流量。但是有些视频无法进行下载,加上下载后视频有水印,这在一定程度上影响了我视频的观看体验。
虽然去水印工具很早就出来了,但是使用时都感觉不尽如人意。保存视频需要观看广告,打开小程序弹窗广告满天飞,界面设计过于冗余,这让我觉得很难用。于是,就有了自己开发小程序的想法。
一切都进展很顺利,小程序主要功能也已经开发完成。就在我准备上架的时候,出现了一个问题,无水印视频无法下载
如图所示
查阅资料得知,小程序想要下载文件,必须要去微信公众平台: 链接,小程序后台添加downloadfile合法域名列表才可以。我刚开始,添加了合法域名列表,认为事情完美解决了,就把小程序给匆匆上线了。哪知道 刚过十分钟,用户就反馈视频无法下载,我心想:“不应该啊,这个问题不是解决了吗?”,怎么还有问题呢?
通过上网查询得知,抖音服务器众多,保存视频的服务器不固定,也就是说无水印视频的域名是不固定的,而且数目不少,我一想,这完了,这基本不可能把白名单做到全覆盖啊。我就开始在网上查资料,功夫不负有心人-----发现可以通过代理来解决这个问题。
如图所示,于是我就开始改造项目
完成这项工作,你需要:
- 一个已经备案过的域名
- 一台服务器
服务器配置步骤:
- 进入服务器管理面板,点击「网站」→「添加站点」
- 选择「传统项目」→「域名」
- 填写域名信息并保存
填写完成之后,去网站根目录,上传php代理文件
php代理文件代码如下:
<?php
// 开启错误报告
error_reporting(E_ALL);
ini_set('display_errors', 1);
// 定义日志文件路径
define('LOG_FILE', __DIR__ . '/download_log.txt');
// 日志函数
function writeLog($message) {
$timestamp = date('Y-m-d H:i:s');
$logMessage = "[$timestamp] $message\n";
// 尝试写入日志
$result = @file_put_contents(LOG_FILE, $logMessage, FILE_APPEND);
// 如果写入失败,输出错误信息
if ($result === false) {
$error = error_get_last();
header('Content-Type: application/json');
echo json_encode([
'error' => 'Failed to write log',
'details' => $error,
'file_exists' => file_exists(LOG_FILE),
'is_writable' => is_writable(LOG_FILE),
'path' => LOG_FILE
]);
exit;
}
}
// 测试日志写入
writeLog('=== Starting download proxy service ===');
// 记录请求信息
writeLog('Request URL: ' . ($_GET['url'] ?? 'No URL provided'));
writeLog('User Agent: ' . ($_SERVER['HTTP_USER_AGENT'] ?? 'No User Agent'));
// 设置CORS头
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET');
header('Access-Control-Allow-Headers: Content-Type');
// 检查URL参数
if (!isset($_GET['url'])) {
writeLog('Error: No URL parameter provided');
header('HTTP/1.1 400 Bad Request');
echo json_encode(['error' => 'URL parameter is required']);
exit;
}
$url = $_GET['url'];
writeLog("Processing URL: $url");
// 初始化CURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
// 获取头信息
writeLog('Fetching headers...');
$result = curl_exec($ch);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($result, 0, $headerSize);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
writeLog("Response HTTP Code: $httpCode");
writeLog("Response Headers: $headers");
if ($httpCode !== 200) {
writeLog("Error: HTTP Code $httpCode");
header('HTTP/1.1 ' . $httpCode);
echo json_encode(['error' => 'Failed to fetch resource', 'code' => $httpCode]);
exit;
}
// 重新设置CURL获取完整内容
curl_setopt($ch, CURLOPT_NOBODY, false);
$result = curl_exec($ch);
if ($result === false) {
$error = curl_error($ch);
writeLog("CURL Error: $error");
header('HTTP/1.1 500 Internal Server Error');
echo json_encode(['error' => 'CURL error', 'details' => $error]);
exit;
}
// 获取内容类型
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
writeLog("Content Type: $contentType");
// 设置响应头
header('Content-Type: ' . $contentType);
echo $result;
// 记录成功
writeLog('Download completed successfully');
curl_close($ch);
?>
编写好代理文件后,如图操作,重启nginx
这个时候还不行,小程序端还没有进行相应的处理
小程序代码如下
// 构建代理URL
buildProxyUrl(originalUrl) {
return `https://你的域名/download.php?url=${encodeURIComponent(originalUrl)}`;
},
const downloadTask = wx.downloadFile({
url: videoUrl,
success: (res) => {
console.log('直接下载结果:', res);
if (res.statusCode === 200 || res.statusCode === 206) {
this.saveToAlbum(res.tempFilePath);
} else {
// 直接下载失败,尝试使用代理
console.log('直接下载失败,尝试代理下载');
const proxyUrl = this.buildProxyUrl(videoUrl);
wx.downloadFile({
url: proxyUrl,
success: (proxyRes) => {
console.log('代理下载结果:', proxyRes);
if (proxyRes.statusCode === 200 || proxyRes.statusCode === 206) {
this.saveToAlbum(proxyRes.tempFilePath);
} else {
wx.hideLoading();
this.handleDownloadError(videoUrl, '下载失败,是否复制链接到浏览器下载?');
}
},
fail: (err) => {
console.error('代理下载失败:', err);
wx.hideLoading();
this.handleDownloadError(videoUrl, '下载失败,是否复制链接到浏览器下载?');
}
}).onProgressUpdate((res) => {
wx.showLoading({
title: `已下载 ${res.progress}%`,
mask: true
});
});
}
},
fail: (err) => {
console.error('直接下载失败:', err);
if (err.errMsg && err.errMsg.includes('url not in domain list')) {
// 域名不在白名单,使用代理下载
console.log('使用代理下载');
const proxyUrl = this.buildProxyUrl(videoUrl);
wx.downloadFile({
url: proxyUrl,
success: (proxyRes) => {
console.log('代理下载结果:', proxyRes);
if (proxyRes.statusCode === 200 || proxyRes.statusCode === 206) {
this.saveToAlbum(proxyRes.tempFilePath);
} else {
wx.hideLoading();
this.handleDownloadError(videoUrl, '下载失败,是否复制链接到浏览器下载?');
}
},
fail: (proxyErr) => {
console.error('代理下载失败:', proxyErr);
wx.hideLoading();
this.handleDownloadError(videoUrl, '下载失败,是否复制链接到浏览器下载?');
}
}).onProgressUpdate((res) => {
wx.showLoading({
title: `已下载 ${res.progress}%`,
mask: true
});
});
} else {
wx.hideLoading();
this.handleDownloadError(videoUrl, '下载遇到问题,是否复制链接到浏览器下载?');
}
}
});
到目前为止,都已经完成,还差最后一步,微信公众平台的域名只支持https模式,所以必须要申请ssl证书
步骤如图:
申请完成后,打开微信公众平台 链接
如图操作即可
之后再下载无水印视频的时候,会通过代理进行下载,也不会出现下载失败的问题。
如果你还有其他问题,欢迎留言