如何使用ASP.NET Core通过IP地址计算站点用户间的地理距离
实现步骤总览
总共分4个核心环节:获取用户真实IP -> IP解析为经纬度坐标 -> 封装距离计算方法 -> 业务逻辑集成
1. 在ASP.NET Core 5中获取用户真实IP
首先要注意如果站点用了反向代理(比如Nginx、Cloudflare),必须先配置转发头,不然拿到的是代理服务器的IP。
配置转发头
修改Startup.cs文件:
// ConfigureServices方法中添加 services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedFor | Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto; // 生产环境建议指定信任的代理IP,测试环境可以清空KnownProxies允许所有 options.KnownProxies.Clear(); }); // Configure方法中,放在所有中间件的最开头添加 app.UseForwardedHeaders();
控制器中获取IP代码
var userIp = Request.HttpContext.Connection.RemoteIpAddress?.ToString(); // 处理IPv6映射的IPv4格式,提取有效IPv4地址 if (userIp != null && userIp.StartsWith("::ffff:")) { userIp = userIp.Substring(7); }
2. IP地址转经纬度坐标
推荐用离线IP地理库实现,无接口请求限制、性能更高,常用开源库为GeoLite2:
- 安装NuGet包:
MaxMind.GeoIP2 - 下载离线IP库文件
GeoLite2-City.mmdb,放入站点App_Data目录 - 封装IP解析方法:
using MaxMind.GeoIP2; public (double Latitude, double Longitude)? GetGeoFromIp(string ip) { try { using var reader = new DatabaseReader("App_Data/GeoLite2-City.mmdb"); var city = reader.City(ip); return (city.Location.Latitude.Value, city.Location.Longitude.Value); } catch { // 内网IP、保留IP等解析失败场景返回null return null; } }
解析得到的经纬度可以存入用户表扩展字段,用户访问/登录时更新即可,无需每次请求重复解析。
3. 计算两个经纬度点之间的地理距离
用Haversine公式计算地球球面两点距离,精度满足普通业务场景,以下示例返回单位为公里:
/// <summary> /// 计算两个经纬度之间的距离,返回单位:公里 /// </summary> public double CalculateDistance(double lat1, double lon1, double lat2, double lon2) { // 地球平均半径,单位:公里 const double earthRadius = 6371; // 角度转弧度 var dLat = ToRadians(lat2 - lat1); var dLon = ToRadians(lon2 - lon1); var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(ToRadians(lat1)) * Math.Cos(ToRadians(lat2)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2); var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); return earthRadius * c; } private double ToRadians(double degrees) { return degrees * Math.PI / 180; }
4. 业务逻辑集成示例
以查询当前用户和平台其他用户的距离为例:
- 用户访问站点时,获取IP解析为经纬度,更新到对应用户数据
- 从用户表拉取所有存在有效经纬度的其他用户
- 遍历调用
CalculateDistance方法,计算当前用户和每个目标用户的距离 - 按需做排序、筛选(比如仅返回5公里以内的用户)等业务处理
注意事项
- 内网IP(比如127.0.0.1、192.168开头的)无法解析到公网地理位置,本地开发时可以自行写死测试经纬度
- GeoLite2库每月更新一次,定期更新mmdb文件可以提升IP解析精度
- 如果需要更高精度的国内IP解析,可以替换为国内的离线IP库,整体逻辑保持不变,仅更换解析类库即可
内容的提问来源于stack exchange,提问作者Pouriya
相关产品推荐
相关产品推荐

