本帖最后由 苏紫方璇 于 2026-6-30 00:55 编辑
为什么做这个接口?解决了什么问题?
在Apple Music下载的无损音乐,存在本地太费内存了, 于是这个接口应运而生,完美解决了需要本地24小时开机和设备限制的场景
![]()
接口是否安全?
该接口基于CloudflareR2存储和Vercel实现,音乐存储在CloudflareR2,接口部署在Vercel,R2访问令牌填到Vercel,这个过程中除了你自己,没有人知道调用接口和R2访问令牌
![]()
部署简单吗? 需要收费吗?
部署很简单,你只需要具备CloudflareR2存储和Vercel账号,在github克隆本项目,就可以使用Vercel开始部署,填写相关的R2访问令牌,就可以调用接口了,这两个服务商都提供了免费额度,个人使用完全没问题
![]() ![]()
适合什么人部署?
适合有自己音源的,不想本地24小时开机,想随时随地的听歌,打造自己的音乐播放器
![]()
音乐文件文件链接会被滥用吗?
这个完全不会, 每一次请求都有签名安全机制,且每一次请求都不一样,这个接口会自动处理,哪怕你分享音乐文件链接出去了,过一会就失效了, 彻底兼并链接正确使用以及链接被盗用的情况
部署项目直达:https://github.com/es3344520/Online-Music
![]()
部署之后只有2个接口,使用非常简单,只做这两件事情,下面是接口参考调用方式
https://your-vercel-domain.vercel.app/api/music?action=fetc 该接口负责获取你的R2文件列表
https://your-vercel-domain.vercel.app/api/music?action=get&file= 该接口负责获取你的文件播放链接
[JavaScript] 纯文本查看 复制代码 const { S3Client, ListObjectsV2Command, GetObjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
module.exports = async (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
if (req.method === 'OPTIONS') {
return res.status(200).end();
}
const {
R2_ACCOUNT_ID,
R2_ACCESS_KEY_ID,
R2_SECRET_ACCESS_KEY,
R2_BUCKET_NAME,
R2_CUSTOM_DOMAIN: rawCustomDomain
} = process.env;
const R2_CUSTOM_DOMAIN = rawCustomDomain ? rawCustomDomain.trim() : undefined;
const s3Client = new S3Client({
region: 'auto',
endpoint: `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: R2_ACCESS_KEY_ID,
secretAccessKey: R2_SECRET_ACCESS_KEY,
},
});
const { action, file } = req.query;
if (!action || action === 'fetch') {
const command = new ListObjectsV2Command({ Bucket: R2_BUCKET_NAME });
const response = await s3Client.send(command);
const files = response.Contents
?.filter(item => !item.Key.endsWith('/'))
.map(item => item.Key) || [];
return res.status(200).json({ success: true, files });
}
if (action === 'get') {
const command = new GetObjectCommand({ Bucket: R2_BUCKET_NAME, Key: file });
const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 600 });
let finalUrl = signedUrl;
if (R2_CUSTOM_DOMAIN) {
const url = new URL(signedUrl);
url.hostname = R2_CUSTOM_DOMAIN;
finalUrl = url.toString();
}
return res.status(200).json({ success: true, url: finalUrl });
}
};
|