diff --git a/.gitignore b/.gitignore index f511187..77792ee 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,9 @@ node_modules/ .claude/ -# MapProxy tile cache +# Tile proxy disk cache tiles/cache/ +tile-proxy/cache/ # TODO: where does this rule come from? docs/_book diff --git a/frontend/App.vue b/frontend/App.vue index 3df7a7d..e4c3328 100644 --- a/frontend/App.vue +++ b/frontend/App.vue @@ -104,6 +104,9 @@ import { ref, computed, onMounted, watch } from 'vue' import L from 'leaflet' import 'leaflet/dist/leaflet.css' +// 瓦片代理地址 — 部署到内网其他机器时,将 localhost 改为服务器 IP +const TILE_PROXY_URL = 'http://localhost:8080/tiles/{z}/{x}/{y}{r}.png' + // ── 常量 ──────────────────────────────────────────────────── const TOTAL_VOLS = 63 @@ -268,9 +271,8 @@ function initMap() { attributionControl: false }) - L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { - maxZoom: 18, - subdomains: 'abcd' + L.tileLayer(TILE_PROXY_URL, { + maxZoom: 18 }).addTo(map) L.control.attribution({ prefix: false, position: 'bottomright' }) diff --git a/tile-proxy/docker-compose.yml b/tile-proxy/docker-compose.yml new file mode 100644 index 0000000..23986a3 --- /dev/null +++ b/tile-proxy/docker-compose.yml @@ -0,0 +1,15 @@ +services: + tile-proxy: + image: nginx:alpine + ports: + - "8080:80" + volumes: + - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro + - ./cache:/var/cache/nginx/tiles + restart: unless-stopped + # 健康检查:每30秒确认代理存活 + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost/health"] + interval: 30s + timeout: 5s + retries: 3 diff --git a/tile-proxy/nginx.conf b/tile-proxy/nginx.conf new file mode 100644 index 0000000..30b1d5e --- /dev/null +++ b/tile-proxy/nginx.conf @@ -0,0 +1,54 @@ +# 磁盘缓存配置 +# levels=1:2 两级目录结构,避免单目录文件过多 +# keys_zone=20m 内存索引 20MB,约可索引 160,000 个瓦片 +# max_size=10g 磁盘缓存上限 10GB(约覆盖全国 z0-z14 级别) +# inactive=30d 30天未访问的瓦片自动清理 +proxy_cache_path /var/cache/nginx/tiles + levels=1:2 + keys_zone=tiles_cache:20m + max_size=10g + inactive=30d + use_temp_path=off; + +server { + listen 80; + + # 使用 Docker 内置 DNS 解析上游域名 + resolver 127.0.0.11 valid=300s; + resolver_timeout 5s; + + location /tiles/ { + # 去掉 /tiles/ 前缀,补全底图样式路径后转发 + rewrite ^/tiles/(.*)$ /light_all/$1 break; + + proxy_pass https://a.basemaps.cartocdn.com; + proxy_ssl_server_name on; + + # 缓存配置 + proxy_cache tiles_cache; + proxy_cache_key "$uri"; + proxy_cache_valid 200 30d; + proxy_cache_lock on; # 同一瓦片并发请求只放行一个去上游 + proxy_cache_lock_timeout 5s; + + # 上游故障时继续提供过期缓存,避免地图空白 + proxy_cache_use_stale error timeout updating + http_500 http_502 http_503 http_504; + proxy_cache_background_update on; + + # 超时设置 + proxy_connect_timeout 5s; + proxy_read_timeout 15s; + + # 响应头 + add_header Access-Control-Allow-Origin *; + add_header X-Cache-Status $upstream_cache_status; + expires 30d; + } + + # 健康检查 + location /health { + return 200 "ok\n"; + add_header Content-Type text/plain; + } +} diff --git a/tiles/docker-compose.yml b/tiles/docker-compose.yml deleted file mode 100644 index 461a0be..0000000 --- a/tiles/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: '3.8' - -services: - mapproxy: - image: kartoza/mapproxy:latest - ports: - - "8080:8080" - volumes: - - ./mapproxy/mapproxy.yaml:/srv/mapproxy/mapproxy.yaml - - ./mapproxy/seed.yaml:/srv/mapproxy/seed.yaml - - ./cache:/srv/mapproxy/cache_data - environment: - - MAPPROXY_PROCESSES=4 - restart: unless-stopped diff --git a/tiles/mapproxy/mapproxy.yaml b/tiles/mapproxy/mapproxy.yaml deleted file mode 100644 index 1189546..0000000 --- a/tiles/mapproxy/mapproxy.yaml +++ /dev/null @@ -1,34 +0,0 @@ -services: - tms: - grids: [GLOBAL_WEBMERCATOR] - origin: nw - restful: true - -layers: - - name: carto_light - title: CartoDB Positron (Cached) - sources: [carto_light_cache] - -caches: - carto_light_cache: - grids: [GLOBAL_WEBMERCATOR] - sources: [carto_light_source] - cache: - type: file - directory: /srv/mapproxy/cache_data/carto_light - -sources: - carto_light_source: - type: tile - url: https://a.basemaps.cartocdn.com/light_all/%(z)s/%(x)s/%(y)s.png - grid: GLOBAL_WEBMERCATOR - -grids: - GLOBAL_WEBMERCATOR: - srs: EPSG:3857 - origin: nw - -globals: - cache: - base_dir: /srv/mapproxy/cache_data - lock_dir: /srv/mapproxy/cache_data/.locks diff --git a/tiles/mapproxy/seed.yaml b/tiles/mapproxy/seed.yaml deleted file mode 100644 index d0e7f25..0000000 --- a/tiles/mapproxy/seed.yaml +++ /dev/null @@ -1,13 +0,0 @@ -seeds: - carto_light_seed: - caches: [carto_light_cache] - grids: [GLOBAL_WEBMERCATOR] - coverages: [china_coverage] - levels: - from: 1 - to: 10 - -coverages: - china_coverage: - bbox: [73.0, 18.0, 135.0, 54.0] - srs: EPSG:4326