ShipxyAPI 全局对象提供地图、船位、轨迹等能力。在官方示例代码中,API Key 以两种方式暴露在前端:ak 参数在前端仍可见(靠域名绑定使其离开授权域名即失效)。map.yourcompany.com),可同时绑定测试域名localhost,生产密钥绑定正式域名即使后续方案都不做,这一条也必须落实。
此方案只解决"密钥不进代码仓库"的问题。密钥下发到浏览器后仍可被该用户本人看到,因此必须与第一层(域名绑定)配合使用。
ak 参数和 JS 库的 k 参数仍然出现在前端。如果业务 要求密钥彻底不出服务器,可以通过全后端代理实现:后端代理 JS 库加载、瓦片请求、数据接口三个层面,前端全程不接触真实密钥。| 暴露点 | 原始方式 | 全代理方式 |
|---|---|---|
| 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)来跳过前端权限校验,详见下文。
mapTypes 包含 MT_SEA 时,才进入海图加载和权限判断:| 条件 | 校验行为 |
|---|---|
不包含 MT_SEA | 不加载海图,不执行海图权限校验 |
包含 MT_SEA,且 ShipxyOptions.tiles.seaTileUrl 包含 shipxy.com | 调用 ShipxyAPI.getUserPower(ak);仅当 power.seachart == 1 时通过 |
包含 MT_SEA,且该配置地址不包含 shipxy.com | 按自定义瓦片源处理,跳过 SDK 这一层的海图权限校验 |
重要:这里跳过的是前端 SDK 的权限判断,不代表船讯网服务端免鉴权。如果自定义地址实际反向代理到船讯网,仍需满足上游服务的 Key、权限及白名单要求。
tileLayerShipxyOptions.tiles.seaTileUrl;如果该配置仍是船讯网地址,API 用户仍需通过 getUserPower(ak) 校验。在全代理模式下, ak为占位值,getUserPower(ak)调用将失败。因此方式一不适合全代理方案,应使用方式二。
shipxy.com 时,SDK 按自定义瓦片源处理,不执行这一层 getUserPower(ak) 校验。全代理方案应使用方式二:将 seaTileUrl指向后端代理路径(如/proxy/shipxy-tile/tile.c?...),既改变瓦片请求地址,又跳过前端海图权限校验。其他功能如需要 Key,仍应按其要求配置。
| 维度 | 方式一(tileLayer 构造器) | 方式二(ShipxyOptions 覆盖) |
|---|---|---|
| 修改瓦片地址 | 是 | 是 |
| 跳过前端权限校验 | 否(仍需 getUserPower(ak)) | 是(URL 不含 shipxy.com 即跳过) |
| 全代理方案适用性 | 不适用(ak 占位导致校验失败) | 适用(推荐) |
| 执行时机 | 地图初始化时 | SDK 加载后、地图初始化前 |
| 维度 | 全代理方案 | 分层防护方案(第三~五章) |
|---|---|---|
| 密钥暴露程度 | 完全不出服务器 | JS/瓦片中可见,但靠域名绑定失效 |
| 实现复杂度 | 高(需代理 JS、瓦片、数据三层) | 中(仅代理数据接口) |
| 瓦片性能 | 增加一跳延迟,带宽成本上升 | 瓦片直连,无额外开销 |
| JS 库更新 | 需注意代理后 JS 内容修改的兼容性 | 原样加载,无兼容风险 |
| 安全等级 | 最高 | 够用(域名绑定 + 数据代理) |
api.shipxy.com 替换为 /proxy/shipxy-data),需确认库内部的所有 URL 构建逻辑都走替换后的路径。建议逐功能测试:地图加载、区域船、轨迹查询、气象图层Cache-Control 响应头(如 max-age=86400),利用浏览器缓存减少重复请求ak 占位值传递:库内部使用 ak 构建 URL 时,占位值会出现在请求中。后端代理需要识别占位值并替换为真实密钥,而非简单追加mapTypes 包含 MT_SEA 且 ak 为占位值时,SDK 会调用 getUserPower(ak) 校验海图权限,该调用会失败。必须使用 6.2 节方式二(覆盖 ShipxyOptions.tiles.seaTileUrl 为非 shipxy.com 地址)来跳过前端权限校验。使用方式一(tileLayer 构造器)无法跳过此校验| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Node.js / Express | 已有 Node 技术栈 | 代码灵活,中间件生态丰富 | 需维护 Node 服务 |
| Java / Spring Boot | 已有 Java 技术栈 | 企业级方案,权限集成方便 | 启动重,部署较繁琐 |
| Python / Flask | 已有 Python 技术栈 | 轻量快速,适合小项目 | 并发能力有限 |
| Nginx + Lua | 只需代理无需业务逻辑 | 无代码,性能高 | 参数注入需 Lua 扩展 |
ak 参数通过后端下发,非硬编码/proxy/shipxy-api.js 代理加载,URL 无密钥ShipxyOptions.tiles.seaTileUrl 已覆盖为代理路径(非 shipxy.com 地址),跳过前端海图权限校验ShipxyOptions.shipDataServer 数据服务地址已覆盖为代理路径ak 参数使用占位值,后端代理识别并替换为真实密钥mapTypes 包含 MT_SEA 时,确认海图权限校验已通过方式二跳过(而非依赖 tileLayer 构造器)Cache-Control 响应头ak 参数在前端无法隐藏,怎么办?ak 必须在前端传给 ShipxyAPI.Map,这是该版本 API 的机制。防护重心放在"域名绑定"上——密钥离开授权域名即失效,明文可见但不影响安全。ak 通过后端下发而非硬编码,配合域名绑定即可。ak 传占位值(如 "proxied"),所有实际请求都经过后端代理。代理层识别占位值并替换为真实密钥,前端全程不接触真实密钥。这种方式下 ak 虽然出现在前端代码中,但只是一个无意义的占位字符串。Cache-Control 响应头利用浏览器缓存,并可考虑在 Nginx 层做磁盘缓存。如果带宽预算有限,可以只代理 JS 库和数据接口,瓦片走直连 + 域名绑定。mapTypes 包含 MT_SEA 但 ak 为占位 值,SDK 调用 getUserPower(ak) 校验海图权限时失败。解决方案:在地图初始化前,使用方式二覆盖 ShipxyOptions.tiles.seaTileUrl 为非 shipxy.com 的代理地址,SDK 会按自定义瓦片源处理,跳过前端海图权限校验(详见 6.2 节)。注意不要使用 tileLayer 构造器(方式一),它无法跳过此校验。