1. 7 海图GIS平台开发
Shipxy
  • 船讯网API服务概述
  • 文档目录
  • 注册与创建应用
  • 多语言SDK引入
  • 标准API服务
    • 1 船舶查询
      • 1.1 船舶位置查询
        • 1.1.1 单船位置查询
        • 1.1.2 多船位置查询
        • 1.1.3 船队位置查询
      • 1.2 船舶模糊查询
      • 1.3 周边船舶查询
      • 1.4 区域船舶查询
      • 1.5 船舶船籍查询
      • 1.6 船舶档案查询
      • 1.7 档案服务扩展
    • 2 港口查询
      • 2.1 港口信息查询
      • 2.2 港口当前靠泊船查询
      • 2.3 港口当前到锚船查询
      • 2.4 港口预抵船舶查询
    • 3 历史行为
      • 3.1 船舶历史轨迹查询
      • 3.2 船舶互相搭靠记录查询
    • 4 挂靠记录
      • 4.1 船舶历史挂靠记录
      • 4.2 船舶挂靠指定港口记录
      • 4.3 船舶当前挂靠信息
      • 4.4 港口挂靠历史船舶
    • 5 航线规划
      • 5.1 点到点航线规划
      • 5.2 港到港航线规划
      • 5.3 预计到达时间(ETA)查询
    • 6 天气气象
      • 6.1 新全球气象
        • 6.1.1 实时气象数据
        • 6.1.2 未来气象预报
      • 6.2 全球台风
        • 6.2.1 获取全球台风列表
        • 6.2.2 获取单个台风信息
      • 6.3 国内港口潮汐
        • 6.3.1 查询国内潮汐观测站列表
        • 6.3.2 查询单个观测站潮汐详情
      • 6.4 全球港口潮汐
        • 6.4.1 查询全球潮汐观测站列表
        • 6.4.2 查询单个观测站潮汐详情
      • 6.5 海区气象
      • 6.6 单点海洋气象
      • 6.7 历史气象记录
    • 7 海图GIS平台开发
      • 7.1 快速入门:从注册到接入
      • 7.2 地图引擎基础:地图控制与业务绘制
      • 7.3 船位展示服务
      • 7.4 历史轨迹服务
      • 7.5 图层与气象服务
      • 7.6 航线绘制与区域回放服务
      • 7.7 Vue项目接入指南
      • 7.8 API Key后端代理接入
      • 7.9 坐标系转换指南
      • 7.10 私有化部署开发指南
        • 01 私有化地图加载绘制
        • 02 船舶与轨迹绘制实践
        • 03 气象图层效果绘制
    • 8 海事数据
      • 8.1 航行警告查询
    • 9 监控推送
      • 9.1 监控船队管理
        • 9.1.1 创建船队
        • 9.1.2 更新船队信息
        • 9.1.3 查询船队
        • 9.1.4 删除船队
        • 9.1.5 船队船舶增加
        • 9.1.6 船队船舶批量更新
        • 9.1.7 船队船舶删除
      • 9.2 区域监控推送
        • 9.2.1 区域创建
        • 9.2.2 区域更新
        • 9.2.3 区域查询
        • 9.2.4 区域删除
        • 9.2.5 区域监控推送内容
      • 9.3 船舶航速提醒推送
        • 9.3.1 新增船舶订阅
        • 9.3.2 删除订阅船舶信息
        • 9.3.3 查询订阅船舶列表
        • 9.3.4 船舶航速异常推送
      • 9.4 实时船位推送
      • 9.5 船舶到离港事件推送
      • 9.6 船舶动态ETA推送
      • 9.7 船舶AIS信号消失事件推送
      • 9.8 船舶搭靠事件推送
    • 文档附录
      • 船舶类型对照表
      • 服务码返回说明
      • 海区对照表
      • 航行状态对照表
      • 绕航节点清单
      • 航标类型对照表
      • 区域船二进制解析说明
      • 常见问题
  • AI智能体应用
    • AI大模型接入MCP服务
    • 智能体场景应用
      • 运力资源智能体
      • 船舶风控智能体
      • 运输规划智能体
      • 航次时效预测智能体
      • 船舶安全监控智能体
      • 多式联运协同智能体
      • 大宗贸易态势分析智能体
  • 视频监控AI识别预警服务
    • 视频监控服务接入指南
    • 视频监控API服务说明
    • 视频监控场景应用指南
    • 视频监控服务FAQ与最佳实践
  • 场景化开发示例
    • 大宗物流运输智能决策平台
      • 1、港口运力监控与找船
      • 2、船队货运跟踪与 ETA
      • 3、货运异常预警中心
      • 4、大宗航运态势分析与经营决策大屏
      • 5、航次时效预测与滞期费测算
      • 6、航次能效与碳强度管理
    • 海上设施安全监管与决策平台
      • 1、监管区域与事件推送(总览大屏)
      • 2、设施周边安全监控
      • 3、偏航识别与轨迹回放
      • 4、气象海况与航行警告
      • 5、海上安全态势监管大屏与执法效能分析
      • 6、水域通航密度与碰撞风险预测
      • 7、设施运维作业窗口智能排程与船舶调度
  1. 7 海图GIS平台开发

7.8 API Key后端代理接入

适用版本:ElaneMap H5 API 3.5
适用读者:前端开发人员、后端开发人员、运维人员

一、问题分析#

船讯网(shipxy.com)的海图 GIS 平台基于 Leaflet 实现,通过 ShipxyAPI 全局对象提供地图、船位、轨迹等能力。在官方示例代码中,API Key 以两种方式暴露在前端:
这种写法用于本地调试没有问题,但直接用于生产环境存在四重风险:
1.
任何人可见:浏览器"查看源代码"、开发者工具、抓包工具都能直接拿到密钥
2.
被盗用产生费用:密钥绑定调用配额/流量计费,被盗刷会产生经济损失
3.
代码仓库泄露:硬编码进前端代码后随 Git 提交进入仓库,仓库一旦公开密钥永久外泄
4.
无法单独回收:泄露后只能整体更换密钥,影响所有环境

二、架构总览#

整体方案分为三层防护,按"必须做 → 建议做 → 进阶做"递进:
图1-三层防护体系.png
本方案提供两条路径:
分层防护路径(第三~五章):JS 库与瓦片靠域名绑定防护,数据接口走后端代理。实施成本低,但 ak 参数在前端仍可见(靠域名绑定使其离开授权域名即失效)。
全后端代理路径(第六章):JS 库加载、瓦片请求、数据接口三层全部走后端代理,前端全程不接触真实密钥。安全等级最高,但实现复杂度和带宽成本更高。
如果业务要求密钥彻底不出服务器,直接采用第六章的全代理方案。

三、第一层防护(必须做):密钥与域名绑定#

这是最基础、成本最低且最有效的防线。密钥绑定授权域名(Referer 白名单)后,只有来自白名单域名的请求才被放行,密钥即使被复制走也无法在非授权域名下使用。
操作步骤:
1.
申请密钥时或开通服务后,联系船讯网商务/技术支持,将密钥绑定到正式域名(如 map.yourcompany.com),可同时绑定测试域名
2.
本地开发使用的密钥与生产密钥分开申请:开发密钥绑定 localhost,生产密钥绑定正式域名
3.
定期检查密钥调用量,发现异常峰值及时联系船讯网核查
即使后续方案都不做,这一条也必须落实。

四、第二层防护(建议做):密钥不进代码仓库#

4.1 环境变量管理#

无论原生 HTML 还是 Vue/React 工程,密钥都不直接写在提交的代码中:

4.2 后端动态下发#

前端不保存密钥,页面加载时先从自家后端接口获取(可叠加登录态、权限校验、调用日志):
前端代码:
后端代码(Node.js / Express):
此方案只解决"密钥不进代码仓库"的问题。密钥下发到浏览器后仍可被该用户本人看到,因此必须与第一层(域名绑定)配合使用。

4.3 动态加载脚本封装#

封装一个脚本加载工具,避免密钥硬编码在 HTML 中:

五、第三层防护(进阶):后端代理数据接口#

这是核心方案。对于数据类接口(船位、轨迹、气象等 JSON 数据),前端只请求自家后端,自家后端在服务器侧携带密钥去请求船讯网接口,再把结果返回前端。整个链路中密钥不出服务器。

5.1 架构示意#

图2-数据接口代理流程.png
代理层可以顺便实现:
鉴权:登录态校验,未登录用户无法调用
限流:防止接口被恶意刷量
缓存:如气象数据按分钟级缓存,降低密钥配额消耗
审计日志:记录谁在什么时间调用了什么接口

5.2 Node.js(Express)代理示例#

前端调用方式:

5.3 Java(Spring Boot)代理示例#

5.4 Python(Flask)代理示例#

5.5 Nginx 反向代理方案(无代码方案)#

如果只是想快速隐藏数据接口密钥,也可以直接在 Nginx 层注入:
OpenResty(Nginx + Lua)增强版:

六、全后端代理方案:完全隐藏 API Key#

前述方案中,地图初始化的 ak 参数和 JS 库的 k 参数仍然出现在前端。如果业务要求密钥彻底不出服务器,可以通过全后端代理实现:后端代理 JS 库加载、瓦片请求、数据接口三个层面,前端全程不接触真实密钥。

6.1 方案原理#

ShipxyAPI 基于Leaflet 构建,其内部有三个密钥暴露点,逐一用后端代理覆盖:
暴露点原始方式全代理方式
JS 库加载<script src="...?k=密钥">后端代理 JS 文件,前端加载 /proxy/shipxy-api.js
地图瓦片Leaflet 直接请求 tile.c?k=密钥覆盖 options.tileLayer URL,指向 /proxy/tile/
数据接口库内部用 ak 构建 API URL覆盖 ShipxyOptions 服务地址 + 后端代理注入密钥
ak 参数虽然必填,但在全代理模式下传一个占位值即可——因为所有实际请求都经过后端代理,代理层会替换占位值为真实密钥,库内部不会校验 ak 与 k 的一致性。
注意:ak 占位值会导致 SDK 内部的海图权限校验失败,因此必须配合 6.2 节的方式二(覆盖 ShipxyOptions.tiles.seaTileUrl)来跳过前端权限校验,详见下文。

6.2 SDK 海图权限校验机制与瓦片地址配置#

理解 SDK 内部的海图权限校验逻辑,是正确实施全代理方案的前提。以下内容基于内部研发工程师的确认。

6.2.1 海图权限校验逻辑#

当用户配置的 mapTypes 包含 MT_SEA 时,才进入海图加载和权限判断:
条件校验行为
不包含 MT_SEA不加载海图,不执行海图权限校验
包含 MT_SEA,且 ShipxyOptions.tiles.seaTileUrl 包含 shipxy.com调用 ShipxyAPI.getUserPower(ak);仅当 power.seachart == 1 时通过
包含 MT_SEA,且该配置地址不包含 shipxy.com按自定义瓦片源处理,跳过 SDK 这一层的海图权限校验
验证通过后,SDK 将海图层加入图层列表,并注册到地图图层缓存。
重要:这里跳过的是前端 SDK 的权限判断,不代表船讯网服务端免鉴权。如果自定义地址实际反向代理到船讯网,仍需满足上游服务的 Key、权限及白名单要求。

6.2.2 瓦片地址配置方案#

以下两种方式均通过接入页面配置,无需修改 SDK 源码。
方式一:初始化地图时传入 tileLayer
适用于替换当前地图实例的海图瓦片地址:
这种方式只修改实际加载的瓦片地址。权限判断仍读取全局配置 ShipxyOptions.tiles.seaTileUrl;如果该配置仍是船讯网地址,API 用户仍需通过 getUserPower(ak) 校验。
在全代理模式下,ak 为占位值,getUserPower(ak) 调用将失败。因此方式一不适合全代理方案,应使用方式二。
方式二:创建地图前覆盖全局海图瓦片地址(全代理方案推荐)
适用于统一配置自建瓦片服务或反向代理地址。应在 SDK 加载完成后、创建地图前执行:
该配置同时影响默认海图瓦片地址和上述权限判断。当地址不包含 shipxy.com 时,SDK 按自定义瓦片源处理,不执行这一层 getUserPower(ak) 校验。
全代理方案应使用方式二:将 seaTileUrl 指向后端代理路径(如 /proxy/shipxy-tile/tile.c?...),既改变瓦片请求地址,又跳过前端海图权限校验。其他功能如需要 Key,仍应按其要求配置。

6.2.3 两种方式对比#

维度方式一(tileLayer 构造器)方式二(ShipxyOptions 覆盖)
修改瓦片地址是是
跳过前端权限校验否(仍需 getUserPower(ak))是(URL 不含 shipxy.com 即跳过)
全代理方案适用性不适用(ak 占位导致校验失败)适用(推荐)
执行时机地图初始化时SDK 加载后、地图初始化前

6.3 架构示意#

图3-全后端代理架构.png
整条链路中,浏览器发出的所有请求都不含密钥。

6.4 后端代理实现(Node.js / Express)#

6.5 Nginx + OpenResty 全代理方案#

无需写应用代码,用 Nginx + Lua 实现同样的效果:

6.6 前端代码(无密钥)#

Vue3 组件版本:

6.7 全代理方案的权衡#

维度全代理方案分层防护方案(第三~五章)
密钥暴露程度完全不出服务器JS/瓦片中可见,但靠域名绑定失效
实现复杂度高(需代理 JS、瓦片、数据三层)中(仅代理数据接口)
瓦片性能增加一跳延迟,带宽成本上升瓦片直连,无额外开销
JS 库更新需注意代理后 JS 内容修改的兼容性原样加载,无兼容风险
安全等级最高够用(域名绑定 + 数据代理)
瓦片代理是性能敏感点。海图瓦片请求量随缩放级别和视野范围增长,18 级缩放下单屏可能触发数十个瓦片请求。如果带宽预算有限,可以只代理 JS 库和数据接口,瓦片仍走直连 + 域名绑定——密钥虽然出现在瓦片请求 URL 中,但离开授权域名即失效。

6.8 全代理实施要点#

1.
JS 内容修改需测试:后端代理 JS 时如果做了域名替换(将 api.shipxy.com 替换为 /proxy/shipxy-data),需确认库内部的所有 URL 构建逻辑都走替换后的路径。建议逐功能测试:地图加载、区域船、轨迹查询、气象图层
2.
瓦片缓存:代理瓦片时务必设置 Cache-Control 响应头(如 max-age=86400),利用浏览器缓存减少重复请求
3.
ak 占位值传递:库内部使用 ak 构建 URL 时,占位值会出现在请求中。后端代理需要识别占位值并替换为真实密钥,而非简单追加
4.
HTTPS 证书:如果主站使用 HTTPS,代理路径也需在 HTTPS 下,否则浏览器会拦截混合内容
5.
海图权限校验必须跳过:当 mapTypes 包含 MT_SEA 且 ak 为占位值时,SDK 会调用 getUserPower(ak) 校验海图权限,该调用会失败。必须使用 6.2 节方式二(覆盖 ShipxyOptions.tiles.seaTileUrl 为非 shipxy.com 地址)来跳过前端权限校验。使用方式一(tileLayer 构造器)无法跳过此校验
6.
ShipxyOptions 全量覆盖:加载 JS 后,在地图初始化前统一覆盖全局配置,确保瓦片地址和数据服务地址都指向代理:

七、完整方案落地流程#

7.1 环境准备#

1.
向船讯网申请 API Key,提供使用域名或 IP
2.
联系商务/技术支持,将密钥绑定到正式域名(Referer 白名单)
3.
开发密钥与生产密钥分开申请

7.2 前端改造(地图加载部分)#

地图初始化仍然需要在前端进行(Leaflet 机制决定),但密钥从后端获取:

7.3 前端改造(数据请求部分)#

所有数据接口请求改为走自家后端代理:

7.4 后端代理部署#

选择以下任一方案部署代理服务:
方案适用场景优点缺点
Node.js / Express已有 Node 技术栈代码灵活,中间件生态丰富需维护 Node 服务
Java / Spring Boot已有 Java 技术栈企业级方案,权限集成方便启动重,部署较繁琐
Python / Flask已有 Python 技术栈轻量快速,适合小项目并发能力有限
Nginx + Lua只需代理无需业务逻辑无代码,性能高参数注入需 Lua 扩展

7.5 部署架构#

模式 A:分层防护(瓦片直连 + 数据代理)
图4-模式A部署架构.png
模式 B:全后端代理(密钥完全不出服务器)
图5-模式B部署架构.png

八、上线前安全检查清单#

通用项(两种模式都需落实)
生产密钥已与正式域名绑定(Referer 白名单)
代码仓库(含历史提交)中不存在任何真实密钥
开发/测试/生产使用不同密钥
密钥由环境变量/配置中心管理,而非硬编码
后端代理已配置登录态鉴权
后端代理已配置限流策略
已配置密钥调用量监控与异常告警
已制定密钥泄露应急预案(联系船讯网更换密钥的流程与责任人)
分层防护模式额外项
敏感数据接口已走后端代理
前端 ak 参数通过后端下发,非硬编码
全后端代理模式额外项
JS 库已通过 /proxy/shipxy-api.js 代理加载,URL 无密钥
ShipxyOptions.tiles.seaTileUrl 已覆盖为代理路径(非 shipxy.com 地址),跳过前端海图权限校验
ShipxyOptions.shipDataServer 数据服务地址已覆盖为代理路径
ak 参数使用占位值,后端代理识别并替换为真实密钥
mapTypes 包含 MT_SEA 时,确认海图权限校验已通过方式二跳过(而非依赖 tileLayer 构造器)
瓦片代理已设置 Cache-Control 响应头
逐功能验证:地图加载、区域船、轨迹查询、气象图层均正常

九、常见问题#

Q1:地图初始化的 ak 参数在前端无法隐藏,怎么办?
有两种路径处理这个问题:
路径一(分层防护):ak 必须在前端传给 ShipxyAPI.Map,这是该版本 API 的机制。防护重心放在"域名绑定"上——密钥离开授权域名即失效,明文可见但不影响安全。ak 通过后端下发而非硬编码,配合域名绑定即可。
路径二(全后端代理):采用第六章方案,ak 传占位值(如 "proxied"),所有实际请求都经过后端代理。代理层识别占位值并替换为真实密钥,前端全程不接触真实密钥。这种方式下 ak 虽然出现在前端代码中,但只是一个无意义的占位字符串。
Q2:密钥疑似泄露了怎么处理?
第一时间联系船讯网更换密钥;同时检查调用量记录确认损失范围;排查泄露途径(代码仓库、前端页面、外包人员),修复后再启用新密钥。
Q3:后端代理会不会影响性能?
数据接口代理增加一跳延迟(通常几十毫秒),对船位刷新(秒级)影响可忽略;配合分钟级缓存还能降低密钥配额消耗。
瓦片代理是性能敏感点。18 级缩放下单屏可能触发数十个瓦片请求,每个都经后端转发会增加带宽和延迟。如果采用全代理方案,务必设置瓦片的 Cache-Control 响应头利用浏览器缓存,并可考虑在 Nginx 层做磁盘缓存。如果带宽预算有限,可以只代理 JS 库和数据接口,瓦片走直连 + 域名绑定。
Q4:多人协作开发如何分发密钥?
不要通过聊天工具直接发送。使用团队密码管理工具或配置中心下发;每人尽量使用个人开发密钥,便于追溯。
Q5:已经上线的项目如何平滑迁移?
分三步走:第一步立即联系船讯网绑定域名(不改任何代码即可生效);第二步将前端硬编码密钥改为环境变量/后端下发;第三步逐步将数据接口请求迁移到后端代理。每步独立上线,互不阻塞。
Q6:全代理模式下海图不显示,提示权限校验失败怎么办?
这通常是因为 mapTypes 包含 MT_SEA 但 ak 为占位值,SDK 调用 getUserPower(ak) 校验海图权限时失败。解决方案:在地图初始化前,使用方式二覆盖 ShipxyOptions.tiles.seaTileUrl 为非 shipxy.com 的代理地址,SDK 会按自定义瓦片源处理,跳过前端海图权限校验(详见 6.2 节)。注意不要使用 tileLayer 构造器(方式一),它无法跳过此校验。
Q7:跳过前端 SDK 海图权限校验后,船讯网服务端会不会拒绝请求?
跳过的是前端 SDK 层面的权限判断逻辑,不影响后端代理层到船讯网的实际请求。后端代理会注入真实密钥,船讯网服务端按其 Key、权限及白名单规则进行校验。只要密钥本身具备海图权限且域名白名单正确,服务端不会拒绝。
上一页
7.7 Vue项目接入指南
下一页
7.9 坐标系转换指南