Skip to content

Commit c273174

Browse files
committed
feat: 订阅流量信息还原为 profile-web-page-url 响应头, 避免某些客户端出现异常
1 parent 6dc7cc4 commit c273174

4 files changed

Lines changed: 96 additions & 25 deletions

File tree

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store",
3-
"version": "2.20.69",
3+
"version": "2.20.72",
44
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
55
"main": "src/main.js",
66
"scripts": {

backend/src/restful/download.js

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,22 @@ async function downloadSubscription(req, res) {
261261
$arguments.flowUrl,
262262
);
263263
if (flowInfo) {
264-
res.set(
265-
'subscription-userinfo',
266-
normalizeFlowHeader(flowInfo),
267-
);
264+
const headers = normalizeFlowHeader(flowInfo, true);
265+
if (headers?.['subscription-userinfo']) {
266+
res.set(
267+
'subscription-userinfo',
268+
headers['subscription-userinfo'],
269+
);
270+
}
271+
if (headers?.['profile-web-page-url']) {
272+
res.set(
273+
'profile-web-page-url',
274+
headers['profile-web-page-url'],
275+
);
276+
}
277+
if (headers?.['plan-name']) {
278+
res.set('plan-name', headers['plan-name']);
279+
}
268280
}
269281
}
270282
} catch (err) {
@@ -296,12 +308,26 @@ async function downloadSubscription(req, res) {
296308
} else {
297309
subUserInfo = sub.subUserinfo;
298310
}
299-
res.set(
300-
'subscription-userinfo',
301-
normalizeFlowHeader(
302-
[subUserInfo, flowInfo].filter((i) => i).join(';'),
303-
),
311+
312+
const headers = normalizeFlowHeader(
313+
[subUserInfo, flowInfo].filter((i) => i).join(';'),
314+
true,
304315
);
316+
if (headers?.['subscription-userinfo']) {
317+
res.set(
318+
'subscription-userinfo',
319+
headers['subscription-userinfo'],
320+
);
321+
}
322+
if (headers?.['profile-web-page-url']) {
323+
res.set(
324+
'profile-web-page-url',
325+
headers['profile-web-page-url'],
326+
);
327+
}
328+
if (headers?.['plan-name']) {
329+
res.set('plan-name', headers['plan-name']);
330+
}
305331
}
306332

307333
if (platform === 'JSON') {
@@ -573,10 +599,22 @@ async function downloadCollection(req, res) {
573599
.filter((i) => i)
574600
.join('; ');
575601
if (subUserInfo) {
576-
res.set(
577-
'subscription-userinfo',
578-
normalizeFlowHeader(subUserInfo),
579-
);
602+
const headers = normalizeFlowHeader(subUserInfo, true);
603+
if (headers?.['subscription-userinfo']) {
604+
res.set(
605+
'subscription-userinfo',
606+
headers['subscription-userinfo'],
607+
);
608+
}
609+
if (headers?.['profile-web-page-url']) {
610+
res.set(
611+
'profile-web-page-url',
612+
headers['profile-web-page-url'],
613+
);
614+
}
615+
if (headers?.['plan-name']) {
616+
res.set('plan-name', headers['plan-name']);
617+
}
580618
}
581619
if (platform === 'JSON') {
582620
if (resultFormat === 'nezha') {

backend/src/restful/file.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,22 @@ async function getFile(req, res) {
156156
proxy || file.proxy,
157157
);
158158
if (flowInfo) {
159-
res.set(
160-
'subscription-userinfo',
161-
normalizeFlowHeader(flowInfo),
162-
);
159+
const headers = normalizeFlowHeader(flowInfo, true);
160+
if (headers?.['subscription-userinfo']) {
161+
res.set(
162+
'subscription-userinfo',
163+
headers['subscription-userinfo'],
164+
);
165+
}
166+
if (headers?.['profile-web-page-url']) {
167+
res.set(
168+
'profile-web-page-url',
169+
headers['profile-web-page-url'],
170+
);
171+
}
172+
if (headers?.['plan-name']) {
173+
res.set('plan-name', headers['plan-name']);
174+
}
163175
}
164176
}
165177
} catch (err) {

backend/src/utils/flow.js

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@ export function getFlowField(headers) {
99
const keys = Object.keys(headers);
1010
let sub = '';
1111
let webPage = '';
12+
let planName = '';
1213
for (let k of keys) {
1314
const lower = k.toLowerCase();
1415
if (lower === 'subscription-userinfo') {
1516
sub = headers[k];
1617
} else if (lower === 'profile-web-page-url') {
1718
webPage = headers[k];
19+
} else if (lower === 'plan-name') {
20+
planName = headers[k];
1821
}
1922
}
2023

2124
return `${sub || ''}${
2225
webPage ? `; app_url=${encodeURIComponent(webPage)}` : ''
23-
}`;
26+
}${planName ? `; plan_name=${encodeURIComponent(planName)}` : ''}`;
2427
}
2528
export async function getFlowHeaders(
2629
rawUrl,
@@ -318,7 +321,7 @@ export function getRmainingDays(opt = {}) {
318321
}
319322
}
320323

321-
export function normalizeFlowHeader(flowHeaders) {
324+
export function normalizeFlowHeader(flowHeaders, splitHeaders) {
322325
try {
323326
// 使用 Map 保持顺序并处理重复键
324327
const kvMap = new Map();
@@ -366,11 +369,29 @@ export function normalizeFlowHeader(flowHeaders) {
366369
}
367370
}
368371
});
369-
370-
// 拼接标准化字符串
371-
return Array.from(kvMap.entries())
372-
.map(([k, v]) => `${k}=${encodeURIComponent(v)}`) // 重新编码保持兼容性
373-
.join('; ');
372+
const subscriptionUserinfo = {};
373+
const headers = {
374+
'subscription-userinfo': '',
375+
'profile-web-page-url': '',
376+
'plan-name': '',
377+
};
378+
kvMap.forEach((v, k) => {
379+
if (splitHeaders && k === 'app_url') {
380+
headers['profile-web-page-url'] = v;
381+
} else if (splitHeaders && k === 'plan_name') {
382+
headers['plan-name'] = v;
383+
} else {
384+
subscriptionUserinfo[k] = v;
385+
}
386+
});
387+
if (Object.keys(subscriptionUserinfo).length > 0) {
388+
headers['subscription-userinfo'] = Object.entries(
389+
subscriptionUserinfo,
390+
)
391+
.map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
392+
.join('; ');
393+
}
394+
return splitHeaders ? headers : headers['subscription-userinfo'];
374395
} catch (e) {
375396
$.error(`normalizeFlowHeader failed: ${e.message ?? e}`);
376397
return flowHeaders;

0 commit comments

Comments
 (0)