一、为什么需要专门的经纬度校验?
在地图应用、位置服务等开发场景中,经纬度数据的合法性校验至关重要。未经校验的坐标数据可能导致:
-
🗺️ 地图渲染异常
-
📍 位置标记偏移
-
🚫 地理计算错误
-
💥 后端服务报错
二、经纬度校验核心方案
1. 正则表达式校验法(基础版)
/**
* 校验经纬度格式
* @param {number|string} longitude 经度(-180~180)
* @param {number|string} latitude 纬度(-90~90)
* @returns {boolean|Error} 校验通过返回true,失败返回Error对象
*/
function validateCoordinates(longitude, latitude) {
// 经度正则:整数部分0-180,小数部分0-6位
const LONG_REGEX = /^[\+-]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d{1,6})?)$/
// 纬度正则:整数部分0-90,小数部分0-6位
const LAT_REGEX = /^[\+-]?(90(\.0+)?|([1-8]?\d)(\.\d{1,6})?)$/
if (!LONG_REGEX.test(longitude)) {
return new Error(`经度格式错误:应为-180~180,小数位不超过6位,当前值:${longitude}`)
}
if (!LAT_REGEX.test(latitude)) {
return new Error(`纬度格式错误:应为-90~90,小数位不超过6位,当前值:${latitude}`)
}
return true
}
2. 增强版校验(支持多种输入格式)
function advancedCoordinateValidator(lng, lat) {
// 类型检查
if (typeof lng !== 'number' && typeof lng !== 'string') {
throw new TypeError('经度必须为数字或字符串')
}
if (typeof lat !== 'number' && typeof lat !== 'string') {
throw new TypeError('纬度必须为数字或字符串')
}
// 字符串转换与标准化
const longitude = String(lng).trim()
const latitude = String(lat).trim()
// 增强正则(支持科学计数法)
const SCI_REGEX = /^[\+-]?\d+(\.\d+)?([eE][\+-]?\d+)?$/
// 数值范围校验
const lngVal = parseFloat(longitude)
const latVal = parseFloat(latitude)
if (!SCI_REGEX.test(longitude) {
return new Error('经度格式不合法:只允许数字、小数点和科学计数法')
}
if (lngVal < -180 || lngVal > 180) {
return new Error(`经度值越界:有效范围-180~180,当前值:${lngVal}`)
}
if (!SCI_REGEX.test(latitude)) {
return new Error('纬度格式不合法:只允许数字、小数点和科学计数法')
}
if (latVal < -90 || latVal > 90) {
return new Error(`纬度值越界:有效范围-90~90,当前值:${latVal}`)
}
return true
}
三、生产环境最佳实践
1. TypeScript 版本
interface ValidationResult {
isValid: boolean
error?: {
type: 'longitude' | 'latitude'
message: string
}
}
function tsValidateCoords(
longitude: number | string,
latitude: number | string
): ValidationResult {
const lng = Number(longitude)
const lat = Number(latitude)
if (isNaN(lng) || isNaN(lat)) {
return {
isValid: false,
error: {
type: isNaN(lng) ? 'longitude' : 'latitude',
message: '必须为有效数字'
}
}
}
if (lng < -180 || lng > 180) {
return {
isValid: false,
error: {
type: 'longitude',
message: `经度范围应为-180~180,当前值:${lng}`
}
}
}
if (lat < -90 || lat > 90) {
return {
isValid: false,
error: {
type: 'latitude',
message: `纬度范围应为-90~90,当前值:${lat}`
}
}
}
return { isValid: true }
}
2. Vue 自定义指令版
// 注册全局指令
Vue.directive('valid-coords', {
bind(el, binding, vnode) {
const [lng, lat] = binding.value
const result = validateCoordinates(lng, lat)
if (result instanceof Error) {
el.classList.add('invalid-coords')
vnode.context.$emit('coord-error', result.message)
}
}
})
// 使用示例
<template>
<div v-valid-coords="[longitude, latitude]"></div>
</template>
四、测试用例集
describe('坐标校验测试', () => {
test('合法坐标', () => {
expect(validateCoordinates(116.404, 39.915)).toBe(true)
expect(validateCoordinates('-73.985428', '40.748817')).toBe(true)
})
test('非法经度', () => {
expect(validateCoordinates(181, 45)).toBeInstanceOf(Error)
expect(validateCoordinates('-181.123456', 30)).toBeInstanceOf(Error)
})
test('非法纬度', () => {
expect(validateCoordinates(120, 91)).toBeInstanceOf(Error)
expect(validateCoordinates(120, '-90.1234567')).toBeInstanceOf(Error)
})
test('边界值', () => {
expect(validateCoordinates(180, 90)).toBe(true)
expect(validateCoordinates(-180, -90)).toBe(true)
})
})
五、扩展知识
1. 常见坐标格式支持
-
度分秒格式:
40°26'46"N, 79°58'56"W
-
GeoJSON 格式:
[longitude, latitude]
-
WKT 格式:
POINT(longitude latitude)
2. 精度控制方案
function formatCoordinate(value, decimalPlaces = 6) {
const num = parseFloat(value)
return parseFloat(num.toFixed(decimalPlaces))
}
3. 服务端二次校验
// Express 中间件示例
app.use('/api/locations', (req, res, next) => {
const { lng, lat } = req.body
const result = validateCoordinates(lng, lat)
if (result !== true) {
return res.status(400).json({
error: result.message
})
}
next()
})
六、总结与资源
核心要点:
-
始终在前端进行首轮校验
-
正则表达式是最佳工具
-
考虑国际化和不同格式支持
-
服务端必须进行最终校验