确认操作
确定要执行此操作吗?
@@ -490,92 +932,480 @@
-
\ No newline at end of file
+
diff --git a/src/client/public/manifest.json b/src/client/public/manifest.json
new file mode 100644
index 0000000..e0e548d
--- /dev/null
+++ b/src/client/public/manifest.json
@@ -0,0 +1,22 @@
+{
+ "name": "网易云音乐抓包工具",
+ "short_name": "抓包工具",
+ "description": "网易云音乐客户端抓包与调试工具",
+ "start_url": "/",
+ "display": "standalone",
+ "background_color": "#f0f2f5",
+ "theme_color": "#C20C0C",
+ "categories": ["developer tools", "utilities"],
+ "icons": [
+ {
+ "src": "/icon-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ]
+}
diff --git a/src/client/public/sw.js b/src/client/public/sw.js
new file mode 100644
index 0000000..1a4f40c
--- /dev/null
+++ b/src/client/public/sw.js
@@ -0,0 +1,18 @@
+// 无缓存透传 Service Worker
+// 仅用于 PWA 安装能力,不缓存任何资源
+
+self.addEventListener('install', function() {
+ // 立即激活,不等待页面关闭
+ self.skipWaiting();
+});
+
+self.addEventListener('activate', function() {
+ // 接管所有客户端
+ self.clients.claim();
+});
+
+self.addEventListener('fetch', function(event) {
+ // 纯透传:不缓存任何内容,每次都请求网络
+ // 如果网络不可用,请求失败由浏览器自行处理
+ event.respondWith(fetch(event.request));
+});
diff --git a/src/server/hook.js b/src/server/hook.js
index 900597b..7fa8ea4 100644
--- a/src/server/hook.js
+++ b/src/server/hook.js
@@ -311,6 +311,15 @@ hook.request.before = (ctx) => {
break;
}
netease.path = netease.path.replace(/\/\d*$/, '');
+ // Save original URL path for toggle display and normalize prefixes
+ if (netease.crypto === 'eapi') {
+ netease.rawPath = url.pathname || url.path;
+ } else if (netease.crypto === 'xeapi') {
+ netease.rawPath = url.pathname || url.path;
+ if (netease.path.startsWith('/xeapi/')) {
+ netease.path = netease.path.replace(/^\/xeapi\//, '/api/');
+ }
+ }
ctx.netease = netease;
console.log(netease.path, netease.param) // 这里输出了网易云音乐的抓包数据, 重点看这里
}
@@ -328,10 +337,12 @@ hook.request.before = (ctx) => {
(url.path.startsWith('/weapi/') || url.path.startsWith('/api/'))
) {
req.headers['X-Real-IP'] = '118.88.88.88';
+ const weapiUrlPath = url.path;
ctx.netease = {
crypto: url.path.startsWith('/weapi/') ? 'weapi' : 'api',
web: true,
- path: url.path
+ rawPath: url.path.startsWith('/weapi/') ? weapiUrlPath : undefined,
+ path: weapiUrlPath
.replace(/^\/weapi\//, '/api/')
.split('?')
.shift() // remove the query parameters
@@ -400,10 +411,12 @@ hook.request.after = (ctx) => {
const dataToSend = {
timestamp: new Date().toISOString(),
path: netease.path,
+ rawPath: netease.rawPath || undefined,
crypto: netease.crypto || null,
param: netease.param,
response: netease.jsonBody,
- statusCode: proxyRes.statusCode
+ statusCode: proxyRes.statusCode,
+ method: req.method
};
axios.post(`http://localhost:${process.env.PORT || 3000}/api/capture`, dataToSend)
.catch(err => logger.error('Failed to send data to frontend:', err));
@@ -413,11 +426,13 @@ hook.request.after = (ctx) => {
const dataToSend = {
timestamp: new Date().toISOString(),
path: netease.path,
+ rawPath: netease.rawPath || undefined,
crypto: netease.crypto || null,
param: netease.param,
response: null,
statusCode: proxyRes.statusCode,
- error: error.message
+ error: error.message,
+ method: req.method
};
axios.post(`http://localhost:${process.env.PORT || 3000}/api/capture`, dataToSend)
.catch(err => logger.error('Failed to send data to frontend:', err));