记一次反向代理路径问题

Desc

由于实验在云端环境进行,启动 Gradio 后需通过端口转发访问。初此启动发现 css 不能加载,按钮事件也有问题。F12 检查 Network 发现两个 404:

Name Request URL
info https://<forward-ip-port>/info
theme.css https://<forward-ip-port>/theme.css

观察其他 url 发现,完整的代理路径为 https://<forward-ip-port>/codeserver-forward/<ID>/proxy/<proxy>/,其后才是 /info/theme.css 等。正是这多出的一段路径导致请求失败。

其中,css 问题容易解决,修改网页 HTML,将 theme.css 的 <link> 标签替换正确 url 即可。检查控制台报错,未能请求 info 数据则是按钮事件失效的元凶。继续根据输出定位,知 info 由 index.js 请求:

1
2
3
4
5
} else {
response = await fetch_implementation(`${config2.root}/info`, {
headers
});
}

在 F12 工具里补上了 codeserver-forward/<ID>/proxy/<proxy> 这段路由,没什么效果。

接下来尝试了两种方式,i) 替换 index.js; ii) 拦截 index.js 发出的 /info 请求。

Try

替换 index.js 为本地文件

观察 Network,index.js 被分割为多个文件 (命名形如 index-7a48, index-0750 等) 加载,而在 /info 请求前的只有 index-7a48. 手动下载该文件,与 index.js 有些差异,不过大概定位了 /info 请求位置:

1
2
3
}) : te = await e(`.../info`, {
headers: D
}),

虽然不知这样处理是否正确,但是检查了 /info 请求前的其他请求,确实只有 index-7a48 与之相关。本地启动 LiveServer,编写油猴脚本进行替换[1]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ==UserScript==
// @name JS Replace
// @namespace http://tampermonkey.net/
// @version 2024-11-28
// @description try to replace JS on a specific webpage
// @author You
// @match https://<forward-ip-port>/codeserver-forward/<ID>/proxy/<proxy>/*
// @grant none
// @run-at document-start // 让脚本在文档开始时执行
// ==/UserScript==

(function() {
'use strict';

document.querySelectorAll('script[src="https://<forward-ip-port>/codeserver-forward/<ID>/proxy/<proxy>/assets/index-7a48.js"]').forEach(function(script) {
script.remove();
});

// 创建并注入新的JS文件
var newScript = document.createElement('script');
newScript.src = 'http://127.0.0.1:5500/hpccube-forward/index-7a48.js';
newScript.defer = true;
newScript.onload = function() {
// 检查这个脚本是否成功运行了
console.log('New script loaded successfully.');
};
document.head.appendChild(newScript);
})();

这个脚本确实是运行了;但 /info 请求还是按照错误的 url 发。

拦截 /info 请求并替换

手动下载 info 数据,并拦截请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ==UserScript==
// @name Replace URL Requests
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Replace all requests from https://a.com/a to https://b.com/b
// @author You
// @match https://<forward-ip-port>/codeserver-forward/<ID>/proxy/<proxy>/*
// @grant none
// @run-at document-start
// ==/UserScript==

(function() {
'use strict';

// 重写 XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
// 替换 URL
if (url.includes('https://<forward-ip-port>/info')) {
url = url.replace('https://<forward-ip-port>/info', 'http://127.0.0.1:5500/hpccube-forward/info');
}
return originalOpen.apply(this, arguments);
};

// 重写 fetch 方法
const originalFetch = window.fetch;
window.fetch = function(input, init) {
let url = typeof input === 'string' ? input : input.url;
// 替换 URL
if (url.includes('https://<forward-ip-port>/info/info')) {
url = url.replace('https://<forward-ip-port>/info/info', 'http://127.0.0.1:5500/hpccube-forward/info');
}
return originalFetch.apply(this, [url, init]);
};
})();

实测拦截方案成功了,分别向 LiveServer 发了两条 /info 请求,一次 OPTIONS 204,一次 GET 200.

Summary

把 css 和 /info 的问题都解决以后,发现还有不少请求有着与 /info 相同的问题,再改下去意义不大了。

任何通过反向代理的 Web 请求都有可能面临 url 构造错误的问题,在此,Streamlit 做得要比 Gradio 更完善。


  1. 怎么替换网页的 js 油猴脚本 | PingCode智库 ↩︎