用户位置可能会骗你


关于基于用户位置进行编程。这涉及了技术限制、法律问题和隐私权。

位置、位置、位置

有几个常见的例子需要在应用程序中添加基于位置的逻辑:

  • 根据区域设置应用的语言或货币。
  • 向特定国家的人提供折扣。
  • 有一个商店定位器,应该显示用户最近的位置。
  • 天气应用需要依赖位置才能提供任何数据。
  • 出于法律原因进行地理围栏(如显示cookie横幅)。

这只是几个用例,还有很多其他的情况,但从这些例子中,我们可以确定一些共同的主题:

  • 展示/用户体验:使用位置信息改进或简化用户体验。
  • 功能/逻辑:应用程序的业务逻辑根据位置变化。
  • 政策/合规:有法律要求需要包含或排除某些功能。

情况并不总是如此清晰。在某些情况下会有重叠,但重要的是要记住这些区别,因为错误的处理方式会有不同程度的严重性。例如,显示错误的货币并不像误算税率那么严重,而误算税率也不如违反禁运严重。

考虑到这一点,让我们看看我们有哪些选择。

获取用户位置

我知道有四种方法可以访问用户的位置,每种方法都有其优缺点。

  1. 用户报告
  2. 设备启发
  3. IP地址
  4. 边缘计算

从用户获取用户位置

这是指在网站上有一个明确询问用户位置的表单。它可能会提供诸如自动填充地址之类的用户体验改进,但最终,你还是要相信用户提供的信息。

这种方法的好处是很容易开始(一个HTML表单就可以),提供的信息可靠性取决于用户,支持不同位置的灵活性。

最明显的缺点是,如果用户输入错误或遗漏信息,可能不准确。此外,用户很容易提供虚假信息。在某些情况下,这是可以接受的,而在其他情况下则是一个大错误。

例如:

如果你决定采用这种方法,最好使用具有预选选项的表单控件(选择或单选),或集成某种自动完成(位置API)。这提供了更好的用户体验,通常会导致更完整、更可靠、更准确的数据。

从设备获取用户位置

现代设备如智能手机和笔记本电脑可以通过GPSWi-Fi数据、蜂窝塔和IP地址访问其位置信息。作为网络开发人员,我们无法直接访问这些信息,出于安全原因,但有一些事情我们可以做。

首先想到的是浏览器内置的地理定位API。它提供了一种方式,使网站可以通过getCurrentPosition方法请求访问用户位置:

1
2
3
navigator.geolocation.getCurrentPosition(data => {
console.log(data)
})

该函数提供一个包含纬度、经度和其他信息的GeolocationPosition对象:

1
2
3
4
5
6
7
8
9
10
11
12
{
"coords": {
"accuracy": 1153.4846436496573,
"altitude": null,
"altitudeAccuracy": null,
"heading": null,
"latitude": 28.4885376,
"longitude": 49.6407936,
"speed": null
},
"timestamp": 1710198149557
}

太好了!只是有一个问题:

网站首次尝试使用地理定位API时,用户会被提示是否分享他们的信息。

  • 最好的情况:用户理解这个额外步骤并接受。
  • 中等情况:用户感到烦恼,接受或拒绝的几率是50/50。
  • 最坏的情况:用户担心政府监控,假设最坏的情况,并且再也不回到你的应用程序。

使用需要用户验证的API时,通常最好提前让用户知道将会弹出提示框,并且只在你真正需要时触发它。换句话说,不要在应用程序加载时请求访问。等到用户聚焦于位置输入字段时再请求。

从IP地址获取用户位置

如果你不熟悉,IP地址看起来像这样:192.0.2.1。它们用于唯一标识和定位网络中的设备。这是计算机在互联网上通信的方式,每个数据包都包含发送者的IP地址信息。你的家庭互联网调制解调器就是一个具有IP地址的网络设备的好例子。

需要注意的是,你可以从IP地址获取位置信息。每个数字块(用句号分隔)代表一个从宽到细的子网。你可以把它看作是从国家到ISP,再到区域,最后到用户。它不会细化到知道某人的具体地址,但有可能获得城市或邮政编码。

JavaScript可以在Node.js中使用response.socket.remoteAddress访问远程IP。需要注意的是,你并没有真正获取用户的IP地址。你获取的是用户连接的IP地址(以及在他们连接上的其他任何人),通过他们的调制解调器和ISP

1
Internet user -> ISP -> IP address.

单凭IP地址无法知道用户来自哪里。你需要将IP地址子网与已知子网位置的数据库进行匹配。通常不需要维护自己的列表,而是可以下载现有的列表,或向第三方服务查询。

对于基本需求,ip2location.comKeyCDN提供免费、有限的选项。对于依赖于从IP地址确定地理位置或需要更高准确度的应用程序,你会需要更强大的解决方案。

所以现在,我们有一个不需要用户任何操作,并且具有相当高准确度的解决方案。相当高的准确度并不能保证用户的IP地址是准确的,正如我们将看到的那样。

从边缘计算获取用户位置

边缘计算是一种通过最近的服务器对用户请求运行动态服务器端代码的方法。它的工作原理是通过全球分布的服务器或节点网络路由所有请求,并允许网络选择离用户最近的节点。

边缘计算的一个优点是平台无需请求用户权限或查找IP地址就能提供用户位置信息。这是因为每个节点都知道自己的位置。

Akamai的边缘计算平台EdgeWorkers为你提供了一个带有userLocation属性的请求对象。这个属性是一个用户位置对象,看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"areaCodes": ["617"],
"bandwidth": "257",
"city": "CAMBRIDGE",
"continent": "NA", // 北美洲
"country": "US",
"dma": "506",
"fips": ["25"],
"latitude": "42.364948",
"longitude": "-71.088783",
"networkType": "mobile",
"region": "MA",
"timezone": "GMT",
"zipCode": "02114+02134+02138-02142+02163+02238"
}

现在我们有了一个可靠的位置信息来源,且无需太多努力。唯一的问题是,这并不是用户的实际位置。用户位置对象实际上表示的是接收到用户请求的边缘节点的位置。这将是离用户最近的节点,可能在同一个区域。这是一个微妙的区别,但根据你的需求,它可能会产生很大的影响。

为什么我们不能拥有完美的解决方案!

我们已经讨论了一些选项及其优缺点,但这里有一个重要的问题。我们看过的所有选项都不完全可靠。

不能信任用户

如上所述,我们不能信任用户总是诚实地提供他们的实际位置。即使我们能够,他们也可能会犯错误。即使他们不犯错误,有些数据也可能是错误的。

不能信任设备

地理定位API的第一个问题是用户可以拒绝使用它。对此你的回应可能是:“好吧,那他们就不能使用我的应用程序了。”但这也不能解决另一个问题,即地理定位API的信息实际上可以由用户在浏览器设置中覆盖。而且这并不难。

不能信任IP地址

我不确定是否可以欺骗连接到你网站的计算机的IP地址,但用户很容易通过代理客户端路由他们的请求。通常,这被称为虚拟专用网络(VPN)。用户连接到VPN,他们的请求先到达VPN,然后VPN连接到你的网站。结果,你看到的IP地址是VPN的,而不是用户的。这意味着你得到的任何位置信息都是VPN的,而不是用户的。

不能信任边缘计算

边缘计算提供可靠的信息,但这些信息是边缘节点的位置,而不是实际用户的位置。通常,它们可以足够接近,但有可能用户住在一个区域的边界附近,而他们最近的边缘节点在边界的另一侧。如果你基于这些区域差异有不同的行为,那会发生什么?此外,边缘计算并不能免于与IP地址相同的VPN问题。通过Akamai的增强代理检测,你可以识别某人是否在使用VPN,但你仍然无法访问他们的原始IP地址。

我们能做些什么?

所以,有很多获取位置信息的方法,但没有一种是完全可靠的。事实上,浏览器扩展可以轻易让用户绕过我们的努力。这是否意味着我们应该放弃?

不!

我希望让你们更加了解并做好准备。所以让我们来看一些例子。

内容翻译

假设我们有一个用英语编写的网站,但也支持其他语言。我们希望通过加载用户的本地语言来改善用户体验。

我们应该如何对待来自比利时的用户,他们讲荷兰语(弗拉芒语)、法语和德语?我们应该默认使用最常见的语言(荷兰语)吗?还是默认使用网站的默认语言(英语)?

对于页面的第一次渲染,我认为使用默认语言或最佳猜测是安全的,但关键是让用户选择最适合他们的语言(也许他们只会说法语)并在以后的访问中尊重他们的选择。

它可能看起来像这样:

    1. 用户请求网站。
    1. 请求通过边缘计算判断来自比利时。
    1. 边缘计算查找HTTP cookie中的语言偏好。
    1. 如果存在cookie,则使用首选语言。
    1. 更新:如果cookie不存在,请检查Accept-Language Header
    1. 如果Accept-Language Header不存在,则使用英语或荷兰语版本。
    1. 在网站中,向用户提供预定义的支持语言列表(可能使用<select>字段)。
    1. 当用户选择语言偏好时,将值存储在cookie中以供将来会话使用。

在这种情况下,我们结合边缘计算和用户报告来获取位置信息以改善体验。我认为根本不需要使用地理定位API。显示错误语言的风险存在,但成本较低。即使位置信息错误或缺失,网站仍然可以正常工作。

天气应用

在这个例子中,我们有一个基于位置显示天气信息的应用程序。在这种情况下,应用程序需要位置信息才能工作。否则我们怎么能显示天气呢?

在这种情况下,首次加载时仍然可以假设用户的位置。我们可以从边缘计算或IP地址中提取该信息,然后显示(我们认为是)用户的本地天气。此外,由于网站的主要功能依赖于位置,我们可以使用地理定位API来请求更准确的数据。我们还希望提供一个灵活的用户报告选项,以防用户想要其他位置的信息。为此,可以使用一个带自动完成功能的搜索输入,尽可能详细地填写位置信息。如何处理以后的访问可能会有所不同。你可以始终默认显示“本地”天气,或者记住上次访问时的位置。

    1. 用户请求网站。
    1. 在第一次请求时,假设位置信息来自边缘计算或IP地址。
    1. 在第一次客户端加载时,启动地理定位API并在必要时更新信息。
    1. 可以将位置信息存储在cookie中以备将来加载使用。
    1. 对于其他位置搜索,提供一个灵活的输入,自动完成位置信息并在提交时更新应用程序。

这里要注意的重要一点是,应用程序实际上并不关心用户的实际位置。我们只关心有一个位置。用户报告的位置(搜索)优先于从cookie、边缘计算或IP地址获取的位置。

由于天气每天都在变化,还值得考虑缓存策略,以及应用程序应该主要是服务器端渲染还是客户端渲染。

店铺定位器

假设你经营一家有多个分店的实体店。你可能会在网上展示你的产品目录和库存,但一个好的做法是提供有关店内库存的最新信息。为此,你需要知道要显示哪个店铺的库存,并且为了获得最佳用户体验,应该是离用户最近的店铺。

再次强调,预测用户的位置使用边缘计算或IP地址是有意义的。然后,你还想提供一个灵活的输入,允许用户输入他们的位置信息,但任何自动完成都应限制在按距离排序的店铺列表中。启动地理定位API也是个好主意。

这个例子和上一个的区别在于,网站的主要目的是不依赖位置的。因此,你应该等到用户与依赖位置的功能进行交互时才请求用户的位置。换句话说,只在用户聚焦于店铺定位器字段时才请求他们的位置。

区域定价

这个有点棘手,但如果根据用户的位置收取不同的价格,你会怎么做?例如,据报道,一些航空公司和酒店对来自某个地区的用户收取的价格高于其他地区的用户。

撇开道德问题不谈,这是一个关于利润的问题,影响很大。所以,你可能不希望用户通过用户报告的位置信息轻易更改他们的价格。

在这种情况下,你可能只会使用边缘计算或IP地址。用户可以通过VPN绕过它,但这可能是你能做到的最好方法。如果你真的担心避免诈骗者,你可以使用Akamai的增强代理检测,并尝试阻止来自VPN用户的请求,但这可能导致没有销售而不是打折销售。决定权在你。

总结

好了,希望这条漫长而曲折的路将我们带到了同一个地方:细节的神奇之地。

我们仍然没有触及其他几个挑战:

  • 当用户在会话中途更改位置时会发生什么?
  • 如果涉及时区,会发生什么?
  • 如何报告有争议领土的位置信息?

尽管如此,我希望你能从中学到用户位置是如何确定的、面临的挑战以及你可能如何应对各种场景。不幸的是,没有一种正确的方法来处理位置数据。有些场景更适合用户报告,有些更适合设备启发式算法,有些更适合边缘计算或IP地址。在大多数情况下,这是一种组合。

你需要问自己的重要问题是:

  • 你需要的是用户的位置还是任何位置?
  • 数据需要多准确?
  • 如果用户位置被伪造可以吗?

你还需要考虑法律合规、法规、功能性,95%的可靠性是否可以接受?

如果你的任何位置逻辑是出于法律原因,你需要采取措施保护自己。考虑像CCPAGDPR这样的数据隐私法。在服务条款中包含信息,以禁止不当行为。