Skip to content

NeteaseCloudMusicApi 部署指南

关于本指南

本指南详细介绍如何部署 NeteaseCloudMusicApi 服务,包括多种部署方式、安全代理实现、登录方法和安全配置。特别强调了安全性,防止 API 被滥用。

概述

NeteaseCloudMusicApi 是一个基于 Node.js 的网易云音乐 API 服务,通过跨站请求伪造 (CSRF) 和伪造请求头的方式调用官方 API。

重要提示:原项目 Binaryify/NeteaseCloudMusicApi 已于 2024 年 4 月 16 日归档并停止维护。建议使用社区维护的活跃分支,如 NeteaseCloudMusicApiEnhancedBinaryify/NeteaseCloudMusicApi 的 GitLab 镜像。

本指南将详细介绍如何部署该 API 服务,并提供安全的代理服务器实现,支持多种登录方式和严格的安全配置。

环境要求

系统要求

请确保您的系统满足以下最低要求:

  • Node.js: 16+ 版本(推荐 18+)
  • npm: 8+ 版本
  • 操作系统: Windows、macOS、Linux(强烈建议使用中国大陆服务器

快速部署

使用 git clone

1. 安装

shell
# 使用社区维护版本(推荐)
$ git clone https://github.com/neteasecloudmusicapienhanced/api-enhanced.git
$ cd api
$ pnpm i

2. 运行

shell
# 默认端口 3000
$ node app.js

服务器启动默认端口为 3000, 若不想使用 3000 端口 , 可使用以下命令 : Mac/Linux

shell
# 自定义端口(Mac/Linux)
PORT=4000 node app.js

windows 下使用 git-bash 或者 cmder 等终端执行以下命令

shell
# 自定义端口(Windows)
set PORT=4000 && node app.js

服务器启动默认 host 为 localhost,如果需要更改, 可使用以下命令 : Mac/Linux

shell
$ HOST=127.0.0.1 node app.js

windows 下使用 git-bash 或者 cmder 等终端执行以下命令 :

shell
$ set HOST=127.0.0.1 && node app.js

使用 npx 方式运行

支持 npx 方式运行,会自动安装依赖和运行

shell
npx @neteasecloudmusicapienhanced/api@版本号

或者运行

shell
npx @neteasecloudmusicapienhanced/api@latest

此命令每次执行都会使用最新版


Vercel 部署

v4.0.8 加入了 Vercel 配置文件,可以直接在 Vercel 下部署了,不需要自己的服务器(访问 Vercel 部署的接口,需要额外加一个 realIP 参数,如 /song/url?id=1969519579&realIP=116.25.146.177)

v4.29.9 加入了生成随机中国 IP 功能, 在请求时加上 randomCNIP=true 即可使用随机中国 IP, 如 /song/url?id=1969519579&randomCNIP=true

不能正常访问的,绑定下国内备案过的域名,之后即可正常访问

操作方法

  1. fork 此项目
  2. 在 Vercel 官网点击 New Project
  3. 点击 Import Git Repository 并选择你 fork 的此项目并点击import
  4. 点击 PERSONAL ACCOUNTselect
  5. 直接点Continue
  6. PROJECT NAME 自己填, FRAMEWORK PRESETOther 然后直接点 Deploy 接着等部署完成即可

腾讯云 serverless 部署

Vercel在国内访问太慢(不绑定自己的域名的情况下),在此提供腾讯云 serverless 部署方法

操作方法

  1. fork 此项目
  2. 在腾讯云 serverless 应用管理页面( https://console.cloud.tencent.com/sls ),点击新建应用
  3. 顶部创建方式选择Web 应用
  4. 选择Express框架,点击底部下一步按钮
  5. 输入应用名,上传方式选择代码仓库,进行 GitHub 授权(如已授权可跳过这一步),代码仓库选择刚刚 fork 的项目
  6. 启动文件填入:
Shell
#!/bin/bash
export PORT=9000
/var/lang/node16/bin/node app.js
  1. 点击完成,等待部署完成,点击资源列表API网关里的URL,正常情况会打开文档地址,点击文档例子可查看接口调用效果
  • 注意
    • 腾讯云 serverless 并不是免费的,前三个月有免费额度,之后收费
    • 当前(2024-08-24), 用此法创建的话, 会默认关联一个"日志服务-日志主题"(创建过程中没有提醒), 此服务是计量收费的, 若不需要, 可在腾讯云 serverless 应用管理页面( https://console.cloud.tencent.com/sls ), 点击应用名, 点击"日志服务"标签, 点击"日志主题", 点击"删除"即可删除

Docker 部署(已失效)

Docker 部署选项

1. 使用官方镜像

bash
# 拉取镜像(使用社区维护版本)
docker pull qiu8310/netease_cloud_music_api

# 运行容器
docker run -d -p 3000:3000 --name netease_api qiu8310/netease_cloud_music_api

2. 自定义构建

创建 Dockerfile

dockerfile
FROM node:18-alpine

WORKDIR /app

# 复制 package.json 并安装依赖
COPY package*.json ./
RUN npm ci --only=production

# 复制源代码
COPY . .

# 暴露端口
EXPOSE 3000

# 启动应用
CMD ["node", "app.js"]

构建并运行:

bash
docker build -t my-netease-api .
docker run -d -p 3000:3000 --name my-netease-api my-netease-api

3. Docker Compose

创建 docker-compose.yml

yaml
version: '3.8'
services:
  netease-api:
    image: qiu8310/netease_cloud_music_api
    ports:
      - "3000:3000"
    environment:
      - PORT=3000
      - HOST=0.0.0.0
    restart: unless-stopped
    # 限制资源使用
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '0.5'

启动:

bash
docker-compose up -d

PM2 进程管理

生产环境推荐

使用 PM2 确保服务稳定运行和自动重启:

bash
# 全局安装 PM2
npm install -g pm2

# 启动服务
pm2 start app.js --name "netease-api"

# 设置开机自启
pm2 startup
pm2 save

# 查看服务状态
pm2 status

# 查看日志
pm2 logs netease-api

安全代理服务器实现

安全警告

绝对不要直接暴露 NeteaseCloudMusicApi 服务到公网! 必须通过代理服务器进行访问控制、身份验证和请求过滤。

为什么需要代理服务器?

  1. 防止滥用:限制只有你的网站可以调用 API
  2. 身份隔离:每个用户使用独立的登录会话
  3. 安全加固:添加额外的安全层,防止直接攻击
  4. 功能扩展:支持多种登录方式和人机验证处理

Node.js 代理服务器(推荐)

完整 Node.js 代理代码
javascript
// secure-proxy.js
const express = require('express');
const httpProxy = require('http-proxy-middleware');
const rateLimit = require('express-rate-limit');
const cors = require('cors');

// ==================== 配置参数 ====================

// 允许访问的域名白名单(必须修改)
const ALLOWED_ORIGINS = [
    'https://your-website.com',
    'https://www.your-website.com',
    'http://localhost:3000' // 开发环境
];

// 允许访问的 IP 白名单(可选)
const ALLOWED_IPS = [
    // '192.168.1.0/24',
    // '203.0.113.0/24'
];

// NeteaseCloudMusicApi 服务地址
const API_TARGET = 'http://localhost:3000';

// ==================== 创建应用 ====================

const app = express();

// ==================== 中间件配置 ====================

// 1. IP 白名单检查
const ipFilter = (req, res, next) => {
    const clientIP = req.ip || req.connection.remoteAddress;
    
    if (ALLOWED_IPS.length === 0) {
        return next(); // 未配置 IP 白名单,跳过检查
    }
    
    const isAllowed = ALLOWED_IPS.some(allowedIP => {
        if (allowedIP.includes('/')) {
            // 处理 CIDR 格式(需要额外的库,这里简化处理)
            return clientIP.startsWith(allowedIP.split('/')[0]);
        }
        return clientIP === allowedIP;
    });
    
    if (!isAllowed) {
        return res.status(403).json({
            code: 403,
            message: 'IP not allowed',
            timestamp: Date.now()
        });
    }
    
    next();
};

// 2. CORS 配置
const corsOptions = {
    origin: (origin, callback) => {
        if (!origin || ALLOWED_ORIGINS.includes(origin)) {
            callback(null, true);
        } else {
            callback(new Error('Not allowed by CORS'));
        }
    },
    credentials: true,
    optionsSuccessStatus: 200
};

// 3. 请求频率限制
const limiter = rateLimit({
    windowMs: 60 * 1000, // 1 分钟
    max: 60, // 每个 IP 最多 60 次请求
    message: {
        code: 429,
        message: 'Too many requests, please try again later.',
        timestamp: Date.now()
    },
    standardHeaders: true,
    legacyHeaders: false,
});

// 4. 安全头设置
app.use((req, res, next) => {
    res.setHeader('X-Content-Type-Options', 'nosniff');
    res.setHeader('X-Frame-Options', 'DENY');
    res.setHeader('X-XSS-Protection', '1; mode=block');
    res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
    next();
});

// ==================== 路由配置 ====================

// 应用中间件
app.use(ipFilter);
app.use(cors(corsOptions));
app.use(limiter);

// 代理所有请求到 NeteaseCloudMusicApi
app.use('/', httpProxy({
    target: API_TARGET,
    changeOrigin: true,
    secure: false,
    onProxyReq: (proxyReq, req, res) => {
        // 添加自定义请求头
        proxyReq.setHeader('X-Forwarded-For', req.ip);
        proxyReq.setHeader('X-Real-IP', req.ip);
    },
    onProxyRes: (proxyRes, req, res) => {
        // 移除或修改响应头
        delete proxyRes.headers['set-cookie']; // 防止 cookie 泄露
    }
}));

// ==================== 错误处理 ====================

app.use((err, req, res, next) => {
    if (err.message === 'Not allowed by CORS') {
        return res.status(403).json({
            code: 403,
            message: 'CORS policy violation',
            timestamp: Date.now()
        });
    }
    
    console.error('Proxy error:', err);
    res.status(500).json({
        code: 500,
        message: 'Internal server error',
        timestamp: Date.now()
    });
});

// ==================== 启动服务器 ====================

const PORT = process.env.PORT || 8080;
app.listen(PORT, '0.0.0.0', () => {
    console.log(`Secure proxy server running on port ${PORT}`);
    console.log(`Proxying to ${API_TARGET}`);
    console.log(`Allowed origins: ${ALLOWED_ORIGINS.join(', ')}`);
});

PHP 代理服务器(备选方案)

完整 PHP 代理代码
php
<?php
/**
 * NeteaseCloudMusicApi 安全 PHP 代理服务器
 * 
 * 安全特性:
 * - 严格的域名/IP 白名单
 * - 请求频率限制
 * - HTTPS 强制重定向
 * - 安全头设置
 * - 错误日志记录
 * - 防止 cookie 泄露
 */

// ==================== 安全检查 ====================

// 强制 HTTPS
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
    $redirectURL = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    header("HTTP/1.1 301 Moved Permanently");
    header("Location: $redirectURL");
    exit();
}

// 设置安全头
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');

// ==================== 配置参数 ====================

// NeteaseCloudMusicApi 服务地址(修改为你的实际地址)
define('API_BASE_URL', 'http://localhost:3000');

// 允许访问的域名白名单(必须修改)
$ALLOWED_DOMAINS = [
    'your-website.com',
    'www.your-website.com',
    'localhost'  // 开发环境
];

// 允许访问的 IP 白名单(可选)
$ALLOWED_IPS = [
    // '192.168.1.0/24',
    // '203.0.113.0/24'
];

// 请求频率限制
define('RATE_LIMIT', 60); // 每分钟最大请求数
define('RATE_WINDOW', 60); // 时间窗口(秒)

// 日志配置
define('ENABLE_LOGGING', true);
define('LOG_FILE', __DIR__ . '/secure_proxy.log');

// ==================== 核心类 ====================

class SecureNeteaseProxy {
    private $allowedDomains;
    private $allowedIPs;
    
    public function __construct($allowedDomains = [], $allowedIPs = []) {
        $this->allowedDomains = $allowedDomains;
        $this->allowedIPs = $allowedIPs;
        $this->setCorsHeaders();
    }
    
    private function setCorsHeaders() {
        $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
        
        if ($this->isAllowedOrigin($origin)) {
            header("Access-Control-Allow-Origin: $origin");
            header('Access-Control-Allow-Credentials: true');
        } else {
            http_response_code(403);
            echo json_encode(['code' => 403, 'message' => 'CORS policy violation']);
            exit;
        }
        
        header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
        header('Access-Control-Allow-Headers: Content-Type, Authorization');
        
        if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            http_response_code(200);
            exit;
        }
    }
    
    private function isAllowedOrigin($origin) {
        if (empty($this->allowedDomains)) {
            return true;
        }
        
        $host = parse_url($origin, PHP_URL_HOST);
        return in_array($host, $this->allowedDomains);
    }
    
    private function isAllowedIP($ip) {
        if (empty($this->allowedIPs)) {
            return true;
        }
        
        foreach ($this->allowedIPs as $allowedIP) {
            if ($this->matchIP($ip, $allowedIP)) {
                return true;
            }
        }
        
        return false;
    }
    
    private function matchIP($ip, $pattern) {
        if (strpos($pattern, '/') !== false) {
            // 简单的 CIDR 匹配(生产环境建议使用专门的库)
            list($subnet, $mask) = explode('/', $pattern);
            $subnet = ip2long($subnet);
            $ipLong = ip2long($ip);
            $mask = ~((1 << (32 - $mask)) - 1);
            return ($ipLong & $mask) === ($subnet & $mask);
        }
        
        return $ip === $pattern;
    }
    
    private function getClientIP() {
        $ipKeys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR'];
        
        foreach ($ipKeys as $key) {
            if (!empty($_SERVER[$key])) {
                $ip = trim(explode(',', $_SERVER[$key])[0]);
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            }
        }
        
        return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
    }
    
    private function isRateLimited($ip) {
        $cacheFile = sys_get_temp_dir() . "/rate_limit_$ip.json";
        
        if (file_exists($cacheFile)) {
            $data = json_decode(file_get_contents($cacheFile), true);
            $now = time();
            
            // 清理过期记录
            $data = array_filter($data, function($timestamp) use ($now) {
                return $timestamp > $now - RATE_WINDOW;
            });
            
            if (count($data) >= RATE_LIMIT) {
                return true;
            }
        } else {
            $data = [];
        }
        
        // 记录当前请求
        $data[] = time();
        file_put_contents($cacheFile, json_encode($data));
        
        return false;
    }
    
    private function log($message, $level = 'INFO') {
        if (!ENABLE_LOGGING) return;
        
        $timestamp = date('Y-m-d H:i:s');
        $ip = $this->getClientIP();
        $logEntry = "[$timestamp] [$level] [IP: $ip] $message" . PHP_EOL;
        
        file_put_contents(LOG_FILE, $logEntry, FILE_APPEND | LOCK_EX);
    }
    
    public function handleRequest() {
        try {
            $clientIP = $this->getClientIP();
            
            // 检查 IP 白名单
            if (!$this->isAllowedIP($clientIP)) {
                throw new Exception('IP not allowed', 403);
            }
            
            // 检查请求频率
            if ($this->isRateLimited($clientIP)) {
                throw new Exception('Rate limit exceeded', 429);
            }
            
            // 获取请求路径
            $path = $_GET['path'] ?? '';
            if (empty($path)) {
                throw new Exception('Missing path parameter', 400);
            }
            
            // 构建 API URL
            $apiUrl = API_BASE_URL . '/' . ltrim($path, '/');
            $queryParams = $_GET;
            unset($queryParams['path']);
            
            if (!empty($queryParams)) {
                $apiUrl .= '?' . http_build_query($queryParams);
            }
            
            // 发送请求
            $response = $this->makeSecureRequest($apiUrl);
            
            $this->log("Request: $apiUrl - Response: " . strlen($response) . " bytes");
            
            // 返回响应(移除敏感头)
            header('Content-Type: application/json; charset=utf-8');
            echo $response;
            
        } catch (Exception $e) {
            $this->handleError($e);
        }
    }
    
    private function makeSecureRequest($url) {
        $ch = curl_init();
        
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => false, // 禁用重定向
            CURLOPT_TIMEOUT => 30,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_HTTPHEADER => [
                'User-Agent: Mozilla/5.0 (compatible; NeteaseProxy/1.0)',
                'Accept: application/json',
                'X-Forwarded-For: ' . $this->getClientIP(),
                'X-Real-IP: ' . $this->getClientIP()
            ],
            CURLOPT_HEADERFUNCTION => function($curl, $header) {
                // 过滤敏感响应头
                if (stripos($header, 'set-cookie:') === 0) {
                    return 0; // 不处理 cookie 头
                }
                return strlen($header);
            }
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        
        curl_close($ch);
        
        if ($response === false) {
            throw new Exception("cURL Error: $error", 500);
        }
        
        if ($httpCode >= 400) {
            throw new Exception("HTTP Error: $httpCode", $httpCode);
        }
        
        return $response;
    }
    
    private function handleError($exception) {
        $code = $exception->getCode() ?: 500;
        $message = $exception->getMessage();
        
        $this->log("Error: $message", 'ERROR');
        
        http_response_code($code);
        header('Content-Type: application/json; charset=utf-8');
        
        echo json_encode([
            'code' => $code,
            'message' => $message,
            'timestamp' => time()
        ], JSON_UNESCAPED_UNICODE);
    }
}

// ==================== 执行代理 ====================

$proxy = new SecureNeteaseProxy($ALLOWED_DOMAINS, $ALLOWED_IPS);
$proxy->handleRequest();
?>

代理服务器配置说明

1. 基本配置

javascript
// Node.js 代理配置
const ALLOWED_ORIGINS = [
    'https://your-website.com',    // 必须使用 HTTPS
    'https://www.your-website.com',
    'http://localhost:3000'        // 开发环境
];

const API_TARGET = 'http://localhost:3000'; // 内网地址,不对外暴露
php
// PHP 代理配置
define('API_BASE_URL', 'http://localhost:3000'); // 内网地址

$ALLOWED_DOMAINS = [
    'your-website.com',
    'www.your-website.com'
];

2. 安全部署

bash
# 设置文件权限
chmod 600 secure-proxy.js  # Node.js
chmod 600 secure_proxy.php # PHP

# 创建日志目录
mkdir -p /var/log/netease-proxy
chmod 700 /var/log/netease-proxy

# 配置防火墙(仅允许必要端口)
ufw allow 8080/tcp  # 代理服务器端口
ufw deny 3000       # 禁止直接访问 API 端口

登录方式详解

1. 手机号密码登录

API 接口

POST /login/cellphone

参数说明

参数类型必选说明
phonestring手机号码
passwordstring密码
countrycodenumber国家区号,默认 86(中国)

安全注意事项

  • 密码加密:前端应使用 HTTPS 传输,不要在客户端存储明文密码
  • 会话管理:登录成功后,将 cookie 存储在安全的 HTTP-only cookie 中
  • 频率限制:对登录接口实施严格的频率限制(如每 5 分钟 3 次)

2. 二维码登录

登录流程

  1. 获取二维码 key:GET /login/qr/key
  2. 生成二维码:https://music.163.com/login?codekey={key}
  3. 轮询检查状态:GET /login/qr/check?key={key}
  4. 获取登录结果

安全实现

javascript
// 二维码登录安全实现
class SecureQRLogin {
    async getQRKey() {
        // 通过安全代理获取 key
        const response = await fetch('/secure-proxy/login/qr/key', {
            credentials: 'include' // 包含 cookie
        });
        return response.json();
    }
    
    async checkQRStatus(key) {
        // 添加防爆破保护
        const response = await fetch(`/secure-proxy/login/qr/check?key=${encodeURIComponent(key)}`, {
            credentials: 'include'
        });
        return response.json();
    }
    
    // 实现轮询逻辑(带超时和错误处理)
    async startPolling(key, onStatusChange, timeout = 120000) {
        const startTime = Date.now();
        
        const poll = async () => {
            if (Date.now() - startTime > timeout) {
                throw new Error('QR code expired');
            }
            
            try {
                const data = await this.checkQRStatus(key);
                onStatusChange(data);
                
                if (data.code === 803) {
                    // 登录成功
                    return data;
                } else if (data.code === 800) {
                    // 二维码过期
                    throw new Error('QR code expired');
                }
                
                // 继续轮询
                setTimeout(poll, 2000);
            } catch (error) {
                console.error('Polling error:', error);
                throw error;
            }
        };
        
        return poll();
    }
}

3. VIP 账号使用

重要说明

要播放 VIP 歌曲,必须使用已登录 VIP 账号的会话。不要在公共代理中使用 VIP 账号,这会导致账号被共享和滥用。

安全的 VIP 使用方案

  1. 个人专用代理:为每个用户创建独立的代理实例
  2. 会话隔离:使用不同的 cookie 存储空间
  3. 账号保护:定期更换密码,监控异常登录
javascript
// 个人专用代理配置示例
const personalProxy = express();

// 为每个用户创建独立的 cookie jar
const userCookieJars = new Map();

personalProxy.use('/api', async (req, res) => {
    const userId = req.headers['x-user-id']; // 从请求头获取用户 ID
    const cookieJar = userCookieJars.get(userId) || new Map();
    
    // 转发请求并使用用户的 cookie
    const apiResponse = await forwardRequestWithCookies(req, cookieJar);
    
    // 保存新的 cookie
    if (apiResponse.headers['set-cookie']) {
        cookieJar.set('netease_cookie', apiResponse.headers['set-cookie']);
        userCookieJars.set(userId, cookieJar);
    }
    
    res.json(apiResponse.body);
});

安全最佳实践

1. 网络隔离

用户浏览器(HTTPS)───▶安全代理服务器(HTTPS)───▶NeteaseCloudMusicApi (HTTP (内网))
  • 代理服务器:暴露在公网,处理所有安全检查
  • API 服务:仅在内网运行,不直接对外提供服务

2. 身份验证

  • API 密钥:为每个客户端分配唯一的 API 密钥
  • JWT 令牌:使用 JWT 进行用户身份验证
  • OAuth 2.0:集成第三方登录

3. 监控和日志

javascript
// 添加详细的日志记录
app.use((req, res, next) => {
    const startTime = Date.now();
    
    res.on('finish', () => {
        const duration = Date.now() - startTime;
        console.log({
            timestamp: new Date().toISOString(),
            method: req.method,
            url: req.url,
            status: res.statusCode,
            duration: `${duration}ms`,
            ip: req.ip,
            userAgent: req.get('User-Agent')
        });
    });
    
    next();
});

4. 定期安全审计

  • 依赖更新:定期更新 Node.js 和 npm 依赖
  • 漏洞扫描:使用 npm auditsnyk 扫描漏洞
  • 配置审查:定期检查安全配置是否正确

故障排除

1. 常见问题

301 重定向错误

问题: API 返回 301 重定向错误

原因: 未正确处理 cookie 或登录状态

解决方案:

  1. 确保在请求中包含正确的 cookie
  2. 检查是否启用了缓存(API 默认缓存 2 分钟)
  3. 在请求 URL 中添加时间戳参数:?timestamp=${Date.now()}
VIP 歌曲无法播放

问题: VIP 歌曲返回空的播放地址

原因:

  1. 未使用 VIP 账号登录
  2. 账号 VIP 已过期
  3. 歌曲版权限制

解决方案:

  1. 确认账号是有效的 VIP 账号
  2. 重新登录 VIP 账号
  3. 检查歌曲的 fee 字段(8 表示 VIP 专享)

2. 性能优化

缓存策略

javascript
// 智能缓存实现
const cache = new Map();

function getCachedData(key, ttl = 300000) { // 5分钟
    const cached = cache.get(key);
    if (cached && Date.now() - cached.timestamp < ttl) {
        return cached.data;
    }
    return null;
}

function setCachedData(key, data) {
    cache.set(key, {
        data: data,
        timestamp: Date.now()
    });
    
    // 清理过期缓存
    if (cache.size > 1000) {
        const keys = Array.from(cache.keys());
        for (let i = 0; i < 100; i++) {
            cache.delete(keys[i]);
        }
    }
}

总结

本指南提供了 NeteaseCloudMusicApi 的安全部署方案,重点强调了:

安全要点

  1. 绝不直接暴露 API 服务:必须通过安全代理
  2. 严格的访问控制:域名/IP 白名单 + 频率限制
  3. HTTPS 全程加密:从用户到代理再到 API
  4. 会话隔离:防止账号信息泄露
  5. VIP 账号保护:避免在公共环境中使用

相关资源

Copyright © 2025 NeteaseMiniPlayer