一、前言
效果:

在实际项目开发中,尤其是无人机巡检系统、GIS系统等场景中,地图瓦片的加载稳定性非常关键。
我们经常会遇到这些问题:
-
瓦片加载失败(白块)
-
接口返回 403(无权限 / 被限制)
-
网络异常导致地图不完整
-
部分区域加载异常但无提示
👉 默认情况下,OpenLayers 并不会暴露 HTTP 状态码,这就导致我们无法感知真实的加载状态。
所以这篇文章的核心就是:
如何在 Vue3 + OpenLayers 中监听瓦片加载状态,并对 200、403、异常等情况进行处理
二、核心思路
OpenLayers 提供了一个关键能力:
source.setTileLoadFunction()
通过重写这个方法,我们可以:
✅ 接管瓦片加载流程
✅ 自定义请求方式(XHR / fetch)
✅ 获取 HTTP 状态码
✅ 做统一异常处理
三、完整示例代码(Vue3 + Composition API)
javascript
<!--
* @Author: 彭麒
* @Date: 2026/3/24
* @Email: 1062470959@qq.com
* @Description: 此源码版权归吉檀迦俐所有,可供学习和借鉴或商用。
-->
<template>
<div class="container">
<div class="w-full flex justify-center flex-wrap">
<div class="font-bold text-[24px]">
Vue3 + Openlayers:监听瓦片地图加载情况,200,403,及其他状态码的处理
</div>
</div>
<div id="vue-openlayers"></div>
<div class="dialog" v-show="isOpen">
出错了,出错了! <br />
<span @click="close">关闭</span>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import 'ol/ol.css'
import { Map, View } from 'ol'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import TileState from 'ol/TileState.js'
// 状态
const map = ref(null)
const mysource = ref(null)
const isOpen = ref(false)
// 关闭弹窗
const close = () => {
isOpen.value = false
}
// 监听瓦片状态
const getStatus = () => {
mysource.value.setTileLoadFunction((tile, src) => {
const xhr = new XMLHttpRequest()
xhr.responseType = 'blob'
xhr.addEventListener('loadend', (evt) => {
const status = evt.currentTarget.status
const data = evt.currentTarget.response
if (status === 200) {
tile.getImage().src = URL.createObjectURL(data)
} else if (status === 403) {
console.log(status)
isOpen.value = true
} else {
tile.setState(TileState.ERROR)
}
})
xhr.addEventListener('error', () => {
isOpen.value = true
tile.setState(TileState.ERROR)
})
xhr.open('GET', src)
xhr.send()
})
}
// 初始化地图
const initMap = () => {
mysource.value = new XYZ({
url: 'https://www.google.com/maps/vt?lyrs=m&gl=en&x={x}&y={y}&z={z}',
crossOrigin: 'anonymous'
})
map.value = new Map({
target: 'vue-openlayers',
layers: [
new TileLayer({
source: mysource.value
})
],
view: new View({
projection: 'EPSG:4326',
center: [-100.15, 16.79],
zoom: 5
})
})
}
// 生命周期
onMounted(() => {
initMap()
getStatus()
})
</script>
<style scoped>
.container {
width: 840px;
height: 570px;
margin: 50px auto;
border: 1px solid #42B983;
position: relative;
}
#vue-openlayers {
width: 800px;
height: 450px;
margin: 0 auto;
border: 1px solid #42B983;
position: relative;
}
.dialog {
width: 600px;
height: 100px;
background: #FF0000;
position: absolute;
left: 120px;
top: 150px;
padding: 30px 30px 0;
}
</style>
四、关键代码解析
1️⃣ setTileLoadFunction(核心入口)
mysource.value.setTileLoadFunction((tile, src) => {})
👉 作用:拦截默认瓦片加载行为
默认是 <img src=xxx>
现在变成 👉 我们自己发请求
2️⃣ 为什么用 XMLHttpRequest?
const xhr = new XMLHttpRequest()
原因:
-
可以拿到
status -
可以处理
error -
支持
blob数据
⚠️ 注意:
fetch 虽然更现代,但在 OpenLayers 中,XHR 更稳定
3️⃣ 处理 200 状态
tile.getImage().src = URL.createObjectURL(data)
👉 手动把 blob 转成图片
4️⃣ 处理 403(重点)
if (status === 403) {
isOpen.value = true
}
常见原因:
-
地图服务未授权
-
key 失效
-
被限流
-
跨域问题
5️⃣ 处理异常
tile.setState(TileState.ERROR)
👉 告诉 OpenLayers:这个瓦片加载失败
否则会一直卡住
五、实际项目中的优化建议(重点)
✅ 1. 防止弹窗疯狂触发
现在代码是:
isOpen.value = true
👉 实际项目建议:
if (!isOpen.value) {
isOpen.value = true
}
✅ 2. 增加重试机制
let retry = 0
const maxRetry = 2
失败自动重试,提高稳定性
✅ 3. 多地图源降级(非常重要)
主地图(Google) → 失败 → 切换天地图 / 高德
👉 企业级项目必须做!
✅ 4. 错误提示升级
不建议用:
<div class="dialog">
建议:
-
ElMessage
-
全局 Toast
-
或埋点上报
六、关于 403 的本质问题(很多人踩坑)
你当前使用的是:
https://www.google.com/maps/vt
⚠️ 注意:
在国内或部分网络环境下:
👉 403 是正常现象
原因:
-
无 API Key
-
被限制访问
-
网络策略问题
七、适用场景
这套方案非常适合:
-
无人机巡检系统
-
WebGIS 平台
-
数字孪生系统
-
地图大屏项目
八、总结
本文核心就一句话:
通过 setTileLoadFunction 接管瓦片请求,从而实现对 HTTP 状态码的精细控 你获得了:
✅ 监听 200 / 403 / error
✅ 控制瓦片加载流程
✅ 提升地图稳定性
✅ 支持企业级扩展