fix(wiki): proxy topology through public gateway

Co-Authored-By: OpenAI Codex <codex@openai.com>
This commit is contained in:
2026-07-15 10:53:18 +08:00
co-authored by OpenAI Codex
parent e3b3a16b10
commit 8d057dbfa3
9 changed files with 81 additions and 5 deletions
+2 -2
View File
@@ -270,9 +270,9 @@ body.wiki-image-lightbox-open { overflow: hidden; }
<div class="topology-embed-shell">
<div class="topology-embed-host">
<iframe class="topology-embed-frame" src="http://192.168.195.241:38080/guanghan_topology_demo.html?mission=GHC-05" title="广寒基地交互式工程拓扑图(GHC-05)" loading="eager" sandbox="allow-scripts allow-same-origin allow-forms" allow="fullscreen"></iframe>
<iframe class="topology-embed-frame" src="http://118.89.192.134:59100/topology/guanghan_topology_demo.html?mission=GHC-05" title="广寒基地交互式工程拓扑图(GHC-05)" loading="eager" sandbox="allow-scripts allow-same-origin allow-forms" allow="fullscreen"></iframe>
</div>
<p class="topology-embed-fallback">如果嵌入视图未能加载,可<a href="http://192.168.195.241:38080/guanghan_topology_demo.html?mission=GHC-05" target="_blank" rel="noopener noreferrer">在新窗口打开交互式拓扑图</a></p>
<p class="topology-embed-fallback">如果嵌入视图未能加载,可<a href="http://118.89.192.134:59100/topology/guanghan_topology_demo.html?mission=GHC-05" target="_blank" rel="noopener noreferrer">在新窗口打开交互式拓扑图</a></p>
</div>
<h2 id="seealso">参见</h2>
+3 -1
View File
@@ -128,7 +128,9 @@
</div>
<script>
const API_BASE = '';
// Keep API calls beside the HTML document so the app works both at the
// service root and behind a reverse-proxy prefix such as /topology/.
const API_BASE = new URL('.', window.location.href).pathname.replace(/\/$/, '');
const SVG_NS = 'http://www.w3.org/2000/svg';
const TYPE_LABELS = { module: '舱段模块', node: '结构节点', vehicle: '着陆器/车辆', equipment: '设备模块' };
const ANCHOR_LABELS = {
+43
View File
@@ -0,0 +1,43 @@
server {
listen 59100;
server_name _;
client_max_body_size 100m;
location = /topology {
return 301 /topology/;
}
location ^~ /topology/ {
proxy_pass http://192.168.195.241:38080/;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Prefix /topology;
}
# Compatibility route for the currently deployed topology image. Newer
# images derive /topology from their document URL and use this same path.
location ^~ /api/v1/bases/guanghan/ {
proxy_pass http://192.168.195.241:38080;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://192.168.195.241:38353;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 90s;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

+2 -1
View File
@@ -37,7 +37,8 @@ class GuanghanTopologySourceTests(unittest.TestCase):
self.assertNotIn("未来西部十字结构", self.html)
def test_page_uses_same_origin_api(self) -> None:
self.assertIn("const API_BASE = ''", self.html)
self.assertIn("new URL('.', window.location.href).pathname", self.html)
self.assertIn("replace(/\\/$/, '')", self.html)
self.assertNotIn("http://localhost:5000", self.html)
def test_page_uses_database_presentation_payload(self) -> None:
+2 -1
View File
@@ -32,7 +32,8 @@ class TopologyApiServingTests(unittest.TestCase):
def test_page_uses_same_origin_api(self) -> None:
html = HTML_PATH.read_text(encoding="utf-8")
self.assertNotIn("http://localhost:5000", html)
self.assertIn("const API_BASE = ''", html)
self.assertIn("new URL('.', window.location.href).pathname", html)
self.assertIn("replace(/\\/$/, '')", html)
def test_config_has_no_default_password(self) -> None:
source = CONFIG_PATH.read_text(encoding="utf-8")
+29
View File
@@ -0,0 +1,29 @@
import unittest
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
DEMO_PATH = PROJECT_ROOT / "data" / "wiki" / "guanghan_topology_demo.html"
GHC05_PATH = PROJECT_ROOT / "data" / "wiki" / "guanghan_ghc05_zh.html"
class WikiTopologyProxyTests(unittest.TestCase):
def test_demo_derives_api_prefix_from_document_url(self):
html = DEMO_PATH.read_text(encoding="utf-8")
self.assertIn("new URL('.', window.location.href).pathname", html)
self.assertIn("replace(/\\/$/, '')", html)
def test_ghc05_embed_uses_public_proxy_instead_of_private_backend(self):
html = GHC05_PATH.read_text(encoding="utf-8")
public_url = (
"http://118.89.192.134:59100/topology/"
"guanghan_topology_demo.html?mission=GHC-05"
)
self.assertEqual(html.count(public_url), 2)
self.assertNotIn("192.168.195.241:38080", html)
if __name__ == "__main__":
unittest.main()