Created
November 22, 2025 12:57
-
-
Save chenxuan520/1790ddf0bdce0fee1b8a2e8f504004c9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Cloudflare Worker - Tianditu (MapWorld) V2 Proxy | |
| * 基于用户提供的 cURL 复刻,使用官方 Web 端 Key | |
| * 坐标系:CGCS2000 (直接作为 WGS84 使用,无需转换,精度完美) | |
| */ | |
| // Nginx 伪装 | |
| const NGINX_HTML = `<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style>body{width:35em;margin:0 auto;font-family:Tahoma,Verdana,Arial,sans-serif;}</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page, the nginx web server is successfully installed and working.</p><p><em>Thank you for using nginx.</em></p></body></html>`; | |
| // 你的 cURL 中使用的关键 Token | |
| const TIANDITU_TK = '75f0434f240669f4a2df6359275146d2'; | |
| export default { | |
| async fetch(request, env, ctx) { | |
| const url = new URL(request.url); | |
| // 1. CORS 配置 | |
| const corsHeaders = { | |
| 'Access-Control-Allow-Origin': '*', | |
| 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', | |
| 'Access-Control-Allow-Headers': 'Content-Type, User-Agent', | |
| }; | |
| if (request.method === 'OPTIONS') { | |
| return new Response(null, { headers: corsHeaders }); | |
| } | |
| // 2. 首页伪装 | |
| if (url.pathname === '/' || url.pathname === '/index.html') { | |
| return new Response(NGINX_HTML, { | |
| headers: { 'Content-Type': 'text/html; charset=UTF-8', 'Server': 'nginx/1.18.0', ...corsHeaders }, | |
| }); | |
| } | |
| // 3. 搜索接口 | |
| if (url.pathname === '/search') { | |
| const query = url.searchParams.get('q'); | |
| if (!query) return new Response('[]', { headers: { 'Content-Type': 'application/json', ...corsHeaders } }); | |
| // ============================================================ | |
| // 构造天地图请求 (严格参考你的 cURL) | |
| // ============================================================ | |
| // 构造 postStr JSON | |
| const postData = { | |
| "keyWord": query, | |
| "level": "11", // 搜索等级,11-12 适合大部分 POI | |
| "mapBound": "-180,-90,180,90", // 范围:全球 (覆盖你的 cURL 中的范围) | |
| "queryType": "1", // 1: 普通关键字搜索 (最通用) | |
| "count": "10", // 返回数量 | |
| "start": "0", | |
| "yingjiType": 1, // 你的参数 | |
| "sourceType": 0, // 你的参数 | |
| "queryTerminal": 10000 // 你的参数 | |
| }; | |
| // 拼接目标 URL | |
| // 注意:这里使用了你的 cURL 中的 v2 接口地址 | |
| const targetUrl = `https://api.tianditu.gov.cn/v2/search?type=query&postStr=${encodeURIComponent(JSON.stringify(postData))}&tk=${TIANDITU_TK}`; | |
| try { | |
| const response = await fetch(targetUrl, { | |
| method: 'GET', // 天地图 V2 是 GET 请求 | |
| headers: { | |
| // 严格复刻你的 Headers | |
| 'Accept': 'application/json, text/plain, */*', | |
| 'Accept-Language': 'zh-CN,zh;q=0.9', | |
| 'Connection': 'keep-alive', | |
| 'Origin': 'https://map.tianditu.gov.cn', | |
| 'Referer': 'https://map.tianditu.gov.cn/', | |
| 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', | |
| 'Sec-Fetch-Dest': 'empty', | |
| 'Sec-Fetch-Mode': 'cors', | |
| 'Sec-Fetch-Site': 'same-site' | |
| } | |
| }); | |
| const data = await response.json(); | |
| // ============================================================ | |
| // 数据清洗 (转换为 Nominatim 格式) | |
| // ============================================================ | |
| const osmResults = []; | |
| // 情况1: 返回 POI 列表 (pois) | |
| if (data.pois && Array.isArray(data.pois)) { | |
| data.pois.forEach((item, index) => { | |
| // 天地图 lonlat 格式通常是 "116.32,39.99" (逗号或空格分隔) | |
| const coords = item.lonlat.split(/[\s,]+/); | |
| if (coords.length >= 2) { | |
| const lng = coords[0]; | |
| const lat = coords[1]; | |
| osmResults.push({ | |
| place_id: (item.userid ? parseInt(item.userid) : Date.now()) + index, | |
| licence: "Data © Tianditu", | |
| osm_type: "node", | |
| osm_id: (item.phone ? parseInt(item.phone.replace(/\D/g,'').slice(0,8)) : Date.now()) + index, | |
| // 构造包围盒 | |
| boundingbox: [ | |
| (parseFloat(lat) - 0.001).toString(), | |
| (parseFloat(lat) + 0.001).toString(), | |
| (parseFloat(lng) - 0.001).toString(), | |
| (parseFloat(lng) + 0.001).toString() | |
| ], | |
| lat: lat, // 原生坐标,无偏差 | |
| lon: lng, // 原生坐标,无偏差 | |
| display_name: `${item.name}, ${item.address || ''}`, | |
| class: "place", | |
| type: item.hotPointID ? "poi" : "unknown", | |
| importance: 0.8 - (index * 0.05), | |
| phone: item.phone || "" | |
| }); | |
| } | |
| }); | |
| } | |
| // 情况2: 返回行政区划 (area) | |
| else if (data.area && data.area.lonlat) { | |
| const coords = data.area.lonlat.split(/[\s,]+/); | |
| if (coords.length >= 2) { | |
| osmResults.push({ | |
| place_id: Date.now(), | |
| licence: "Data © Tianditu", | |
| osm_type: "relation", | |
| osm_id: Date.now(), | |
| boundingbox: null, // 行政区 boundingbox 比较复杂,暂空 | |
| lat: coords[1], | |
| lon: coords[0], | |
| display_name: data.area.name, | |
| class: "boundary", | |
| type: "administrative", | |
| importance: 0.95 | |
| }); | |
| } | |
| } | |
| // 情况3: 统计信息 (statistics) - 有时搜索省份会返回这个 | |
| else if (data.statistics && data.statistics.priorityCitys) { | |
| data.statistics.priorityCitys.forEach((item, idx) => { | |
| const coords = item.lonlat.split(/[\s,]+/); | |
| if (coords.length >= 2) { | |
| osmResults.push({ | |
| place_id: Date.now() + idx, | |
| osm_type: "node", | |
| osm_id: Date.now() + idx, | |
| lat: coords[1], | |
| lon: coords[0], | |
| display_name: item.name, | |
| class: "place", | |
| type: "city", | |
| importance: 0.9 | |
| }); | |
| } | |
| }); | |
| } | |
| return new Response(JSON.stringify(osmResults), { | |
| headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } | |
| }); | |
| } catch (err) { | |
| // 容错返回空 | |
| return new Response(JSON.stringify([]), { headers: { 'Content-Type': 'application/json', ...corsHeaders } }); | |
| } | |
| } | |
| return new Response('Not Found', { status: 404 }); | |
| }, | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment