记一次去水印小程序遇到的downloadFile合法域名的问题和解决方案

先看成品:

35d28dfcf14b87eff989c5300ab03743

我是个抖音重度使用者,平时看到比较有意思或者让人思考的短视频,我总喜欢把他下载到手机相册中,然后分享给朋友。避免视频失效,而且不消耗流量。但是有些视频无法进行下载,加上下载后视频有水印,这在一定程度上影响了我视频的观看体验。

虽然去水印工具很早就出来了,但是使用时都感觉不尽如人意。保存视频需要观看广告,打开小程序弹窗广告满天飞,界面设计过于冗余,这让我觉得很难用。于是,就有了自己开发小程序的想法。

一切都进展很顺利,小程序主要功能也已经开发完成。就在我准备上架的时候,出现了一个问题,无水印视频无法下载

如图所示

image-20250307211356469

查阅资料得知,小程序想要下载文件,必须要去微信公众平台: 链接,小程序后台添加downloadfile合法域名列表才可以。我刚开始,添加了合法域名列表,认为事情完美解决了,就把小程序给匆匆上线了。哪知道 刚过十分钟,用户就反馈视频无法下载,我心想:“不应该啊,这个问题不是解决了吗?”,怎么还有问题呢?

通过上网查询得知,抖音服务器众多,保存视频的服务器不固定,也就是说无水印视频的域名是不固定的,而且数目不少,我一想,这完了,这基本不可能把白名单做到全覆盖啊。我就开始在网上查资料,功夫不负有心人-----发现可以通过代理来解决这个问题。

image-20250307213732671

如图所示,于是我就开始改造项目

完成这项工作,你需要:

  1. 一个已经备案过的域名
  2. 一台服务器

服务器配置步骤:

  1. 进入服务器管理面板,点击「网站」→「添加站点」
  2. 选择「传统项目」→「域名」
  3. 填写域名信息并保存

image-20250307214400079

填写完成之后,去网站根目录,上传php代理文件

image-20250307214631118

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

image-20250307214838569

这个时候还不行,小程序端还没有进行相应的处理

小程序代码如下

  // 构建代理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证书

步骤如图:

image-20250307215733906

申请完成后,打开微信公众平台 链接

如图操作即可

image-20250307220036585

之后再下载无水印视频的时候,会通过代理进行下载,也不会出现下载失败的问题。

如果你还有其他问题,欢迎留言

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是个笨小孩呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值