一个tiktok公开下载器的方案

文章目录

需求背景

实现一个可以下载无水印tiktok公开视频的功能

The TikTok URL link looks like this:

https://vm.tiktok.com/ZSJmdax66/

https://v.douyin.com/RKqEJBV

https://www.tiktok.com/@philandmore/video/6805867805452324102

https://m.tiktok.com/v/6805867805452324102.html

方案

1 py爬虫接口返回视频id

2.1 调用 music.ly 获取下载视频地址信息,直接返回

2.2 或者 http请求来下载文件,返回文件流

第三方公开接口

musical.ly接口直接获取浏览器可下载的接口,只支持tiktok链接,不支持doiuyin

[GET] https://api19-core-c-useast1a.musical.ly/aweme/v1/feed/?aweme_id=7257420363305323794

转流的示例代码

视频链接下载走服务器流量,传文件流给前端

go 复制代码
func (m *FileBiz) DownloadFileV2(ctx *ctrl.Context, fileLink, fileName string) (err error) {

   // 记录下载日志
   record.BusinessLog(record.Debug, "RecordDownloadFileV2", fmt.Sprintf("filePath:%s,wsId:%s,email:%s", fileLink, ctx.GetString("ws_id"), ctx.GetString("email")), "")

   // 获取地址异常
   if fileLink == "" {
   	err = errInfo.ErrFilesNull
   	return
   }

   // 初始化
   request, err := http.NewRequest("GET", fileLink, nil)
   if err != nil {
   	record.BusinessLog(record.Error, "NewRequest", fmt.Sprintf("filePath:%s", fileLink), err.Error())
   	err = errInfo.ErrHttpInit
   	return
   }

   // 执行请求
   clt := http.Client{}
   resp, err := clt.Do(request)
   if err != nil {
   	record.BusinessLog(record.Error, "HttpDp", fmt.Sprintf("filePath:%s", fileLink), err.Error())
   	err = errInfo.ErrHttpDo
   	return
   }

   defer func(Body io.ReadCloser) {
   	errClose := Body.Close()
   	if errClose != nil {
   		record.BusinessLog(record.Error, "FileClose", fmt.Sprintf("filePath:%s", fileLink), errClose.Error())
   	}
   }(resp.Body)

   // 响应头
   ctx.Header("Content-Length", resp.Header.Get("Content-Length"))
   ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName))
   ctx.Header("Content-Type", "application/octet-stream;charset=UTF-8")
   ctx.Header("Set-Cookie", "download=success; Domain=.media.io; Path=/;")

   // 响应流
   written, err := io.Copy(ctx.ResponseWriter(), resp.Body)
   if err != nil {
   	record.BusinessLog(record.Error, "IoCopy", fmt.Sprintf("filePath:%s, written:%d", fileLink, written), err.Error())
   	err = errInfo.ErrResponseWritten
   }

   return
}

下载地址的密钥校验

为了实现这个需求,你需要在前端和后端之间建立一个认证机制。这里是一个简单的实现方法:

  1. 前端和后端约定一个密钥(secret key),并确保只有它们知道这个密钥。
  2. 前端在发起请求时生成一个有时效性的key(例如,使用Unix时间戳),并将其与密钥一起使用某种方式(例如,HMAC)进行加密,生成一个签名。
  3. 前端将生成的key和签名一起作为请求头发送给后端。
  4. 后端收到请求后,从请求头中获取key和签名,然后使用相同的加密方法对key和密钥进行加密,与请求头中的签名进行比较。
  5. 如果签名匹配,检查key是否过期,如果未过期,则接受请求,否则拒绝请求。如果签名不匹配或请求头中的refer与期望的不匹配,拒绝请求。

结果:最后没有使用前端生成的code,还是后端传code,在单独的服务器上做验证和转流,避免影响主服务

PS:永远不要相信前端传的数据,尽量数据校验都放在后端

以下是一个简单的Go实现示例:

go 复制代码
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"net/http"
	"strconv"
	"time"
)

const secretKey = "your-secret-key"
const keyExpiration = 60 // Key expiration time in seconds

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		key := r.Header.Get("X-Key")
		signature := r.Header.Get("X-Signature")
		referer := r.Header.Get("Referer")

		// Check referer
		if referer != "your-expected-referer" {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		// Check key and signature
		if isValidKey(key, signature) {
			fmt.Fprintln(w, "Welcome!")
		} else {
			http.Error(w, "Forbidden", http.StatusForbidden)
		}
	})

	http.ListenAndServe(":8080", nil)
}

func isValidKey(key, signature string) bool {
	// Check key expiration
	keyTime, err := strconv.ParseInt(key, 10, 64)
	if err != nil {
		return false
	}
	if time.Now().Unix()-keyTime > keyExpiration {
		return false
	}

	// Check signature
	mac := hmac.New(sha256.New, []byte(secretKey))
	mac.Write([]byte(key))
	expectedSignature := hex.EncodeToString(mac.Sum(nil))

	return hmac.Equal([]byte(signature), []byte(expectedSignature))
}

这个示例中,后端服务器会检查请求头中的Referer(请求的来源)、有时效性的X-Key和X-Signature。请注意,这只是一个简单的示例,实际应用中可能需要对加密算法和过期时间进行调整。

相关推荐
小于负无穷5 小时前
Go 中 RPC 的使用教程
开发语言·后端·rpc·golang
忍界英雄14 小时前
学习笔记-Golang中的Context
笔记·学习·golang
Python私教17 小时前
Go语言现代web开发09 for 循环语句
java·算法·golang
扬子17 小时前
golang中连接达梦数据库使用域名来代替IP时会出现解析问题
开发语言·数据库·golang
GoppViper1 天前
golang学习笔记20——golang微服务负载均衡的问题与解决方案
开发语言·笔记·后端·学习·微服务·golang·负载均衡
程序者王大川1 天前
【GO开发】MacOS上搭建GO的基础环境-Hello World
开发语言·后端·macos·golang·go
SCBAiotAigc1 天前
golang实现正向代理http_proxy和https_proxy
http·golang·https
__AtYou__1 天前
Golang | Leetcode Golang题解之第406题根据身高重建队列
leetcode·golang·题解
varphp1 天前
模仿抖音用户ID加密ID的算法MB4E,提高自己平台ID安全性
java·前端·后端·python·算法·安全·golang
程序者王大川1 天前
【GO语言】Go语言详解与应用场景分析,与Java的对比及优缺点
java·开发语言·golang