你填进自己的号码,表单拒绝了它,而它到底不喜欢哪一部分,一点线索都没有。你试着带上那个零。再试着不带。你试着加一个加号,再换成两个零。这些里面总有一个最后能过,或者一个都过不了——不管哪种,你结束的时候对发生了什么依然毫无头绪。
一句话总结: 单凭一次拒绝,并不能告诉你这个服务最终拿到的是哪个号码,所以从一条报错里去猜被存下的值,不是一个靠得住的做法。去看表单实际显示给你的东西——国家选择器、输入框自己的提示,以及任何回显给你的确认信息。关于「加国家码时要去掉前导零」或者「加号可以换成两个零」,都不存在通用规则,两者都因国家而异。而一个看起来格式正确的号码,仍然不能证明它可被送达,也不能证明某个具体服务会接受它。
被拒绝并不能告诉你服务存下了什么
这是值得抵抗的那一部分,因为它感觉像在做侦探,实际上大多是在猜。
一次笼统的拒绝,并不能确立你输入的内容是怎么被解读的,不能确立有没有东西被保存下来,也不能确立它为什么失败。有些表单在浏览器里检查形状,在任何内容被发送或存储之前就拒掉。有些会把它读到的内容回显出来。另一些只说号码无效。同样一条干巴巴的提示,既符合「号码被完全按你的本意记录下来、却因为别的原因被拒」,也符合「号码丢了一位」,还符合「号码被按另一个国家来解读」。这几种里哪一种成立,不是这条提示本身能定下来的。
你能做的,是去看表单确实显示出来的那些东西。
那该看哪里
国家选择器。 国际表单常常把号码拆成两部分:一个国家或区号控件,以及一个填其余部分的输入框。这是两个独立的输入,完全可能出现「数字对了、国家错了」的情况。你选的国家会改变其余数字被怎么解读,而 libphonenumber 项目的 FAQ 描述的正是这种依赖关系——所提供的地区决定了开头几位怎么被解读,包括它们究竟会不会被当成国家码。
输入框自己的提示。 占位符文字和格式示例,表明这个表单期待的是什么形状。这是可观察的指引,而不是「界面和服务存下来的东西一致」的证明,也不能确立这个示例对你所在的国家是正确的。如果提示缺失或者看起来不一致,那么这个服务自己的帮助,以及你的号码提供方对这个号码国际形式的说法,都比一条记忆里的规则更可靠。
任何回显给你的确认信息。 有些服务会显示它将要使用的号码,常常是部分遮挡的。读它。完整显示时,它是关于界面持有什么的有力证据;遮挡时,末尾几位相同是线索,而不是唯一的识别。无论哪种,它反映的是表单正在显示的东西,这本身并不构成对它背后存了什么的保证。
账号自己的设置,在你进得去的时候。 如果你是在登录或找回,而不是在注册,那么安全或个人资料界面可能会显示在档的号码,那比任何从报错里推出来的东西都更可靠。它只在账号存在、而且你仍然进得去的时候才有。
前导零没有通用规则
人们反复传的那条建议——加国家码时去掉前导零——在很多国家是对的,在另一些国家是错的,把它当成一条法则来套,就会造出错的号码。
libphonenumber 项目维护着一份程序员关于电话号码的错误认识清单,其中一条,正是「国内号码里的前导零,在从国外拨打时总是可以丢掉」这个想法。意大利提供了它的反例:文档描述了一类自 1998 年起把前缀作为号码一部分的号码,举的例子是国内写作 012345、国际写作 +39012345,零被保留。这几位数字是那份文档里的示例,不是一个可以去拨的号码;要点在于这类号码是存在的——而不是每一个意大利号码都这样。
同一份清单也处理了这套民间说法的另一半。国际号码里的加号并不总能换成 00,因为国际长途前缀因国家而异——日本的是 010,不是 00。
实际的结论并不是你得去学每个国家的规则。而是:一条记忆里的规则,比不上两个更好的参照——输入框自己给出的说明,以及你的号码提供方对这个号码国际形式的表述。填写提供方给出的形式,而不是一个你自己变换过的版本,可以避免造出一个从来就不属于你的号码。
症状指向什么
| 你观察到的 | 它与什么情况相符 | 该检查什么 |
|---|---|---|
| 表单立刻拒绝这个号码 | 可能是这个表单不接受的一种形状;它并不能确立没有东西被发出去 | 输入框的提示或占位符,以及国家选择器 |
| 表单接受了,但验证码一直不来 | 任何数量的原因,包括存下了一个不是你的号码 | 服务显示的目的地,以及那条线路能不能收消息 |
| 只有在带上国家码时才被拒 | 这个输入框可能已经在单独处理国家了 | 输入框旁边有没有一个国家控件 |
| 改对选择器之后被接受了 | 这次修正处理掉了一个可观察的问题 | 现在验证码会不会来;仅凭这次修正还定不下来 |
| 只有在去掉前导零时才被拒 | 这可能是一个保留前导零的国家 | 表单自己给出的示例,而不是一条通用规则 |
| 接受了,验证码也来了,但后来某次尝试失败 | 未必是格式问题 | 这个服务对那串验证码有效期的说法 |
两个值得走一遍的情况
两个都是假设的情形,写出来是为了说明推理过程,不是在报告真实案例。
那个从来没被改过的国家。 有人在旅途中把自己的手机号填进一个表单,而这个表单的国家选择器显示的是他当前所在的国家,不是号码所属的国家。数字是对的。表单可能拒绝它们,也可能接受它们、并按那另一个国家来解读。这两种结果,单独任何一个都不能揭示这些数字是怎么被规范化的。可检查的是输入框旁边那个选择器,以及发送之前显示出来的任何确认信息。把选择器设成号码自己所属的国家,再把确认信息重读一遍,这是该做的修正;至于它能不能解决整个问题,要看下一次尝试,而不是由这次修正来保证。
那个出于原则被去掉的零。 有人持有一个意大利号码,它的前导零确实是其国际形式的一部分,而他在加 +39 的时候把那个零去掉了,因为大家熟悉的建议就是这么说的。他填进去的已经不是同一个号码了。如果表单拒绝它,他可能会花上一阵子,去对这串已被改动的数字做更多的变换。如果表单接受它,接受本身并不揭示这个服务拿它做成了什么,验证码可能到,也可能不到。两种情况下的检查是一样的——把服务显示的任何东西读回来,拿它和自己的提供方对这个号码国际形式的表述去比,而不是和一条经验法则去比。
为什么格式正确不等于保证
有两件不同的事情会被从一个格式良好的号码里读出来,而这两件都不成立。
格式有效不等于号码可被送达。 libphonenumber 的 FAQ 明确指出,一个有效号段是运营商可以从中分配号码的号段,并且直白地说明:不应依赖这个库来判断一个号码当前是否分配给了某个具体的人、以及是否可被送达。一个号码完全可以格式无可挑剔,同时根本不在服务中。
号码正确不等于某个服务会接受它。 各个平台会在格式之上套用自己的规则。一个服务不吭声就收下的号码,另一个可能拒绝,而平台政策只是若干可能原因之一,并不能解释服务之间的每一处差别。如果某个服务给出了关于「这个号码不可用」的具体提示,那么在改动任何东西之前,那类拒绝意味着什么、不意味着什么值得先读。
反过来也成立,这一点不太直观:同一份错误认识清单指出,一个无效号码未必就到不了某个端点,它举的是拨号方面的例子——在某些司法辖区,多出来的数字会被忽略。所以一通电话接通了,并不能证明号码是对的。那个例子讲的是拨号,本文不把它延伸到任何具体服务如何路由一条短信。
当问题不出在格式上
如果号码填对了、也确认过了,而验证码仍然不来,那问题已经转到别处去了。
可能是被寻址的那条线路根本收不了消息,纯流量套餐就是这种情况。可能是验证码去了短信以外的地方,因为一个显示着你号码的界面并不告诉你渠道。可能是验证码到了,却填不进输入框,那是另一个有自己检查清单的问题。也可能是验证码到了并且已经过期,这时该读的是临时号码对「再收一次」能做什么。
本文的局限
本文用 libphonenumber 项目公开的材料,说明常见的号码变换并不通用。它并没有把这个项目当作「任何服务如何校验号码」的描述,本文任何内容也不意味着我们使用这个库。
各国具体的号码编制规则这里没有列出,而且是有意不列:本文不是一份各国编号方案的名录。如果你自己号码的正确国际形式不清楚,那么发给你这个号码的提供方,以及服务自己的帮助,才是解决它的地方。
本文无法告诉你某个具体服务存下了什么。把服务显示的内容当作有用的指引来读,而不是当作它内部存储的证明,也不要从一次拒绝里推断出那个存储。
我们的常见问题讲的是下单这一侧,而工单是处理你在我们这里下的某笔订单的具体问题的途径。
FAQ
我能从报错里推出服务保存了哪个号码吗?
从一条笼统的拒绝里不能,这也是最值得记住的一点。这样一条提示,不会告诉你输入是怎么被读的、有没有被保存,或者是什么失败了。有些表单确实会把它解读出来的内容回显出来,出现这种情况时是有用的。不回显的时候,请读服务显示的目的地,或者在你进得去的时候读账号设置界面上的号码,而不要从报错里去推。
加国家码的时候,我该不该去掉前导零?
有时候该,而且不存在一条永远成立的规则。libphonenumber 项目把「前导零总是可以丢掉」列为一条错误认识,并且给出意大利作为反例:那里的国际形式保留了这个零。请按表单自己显示的示例来,而不要套用一条记忆里的规则。
00 和加号是一回事吗?
不是到处都一样。00 是一个常见的国际长途前缀,但它因国家而异——日本用的是 010。如果一个输入框要求国际格式,填加号的形式更稳妥。
表单接受了我的号码,那它就一定是对的,对吗?
接受意味着这个号码通过了这个表单的检查。它并不能确立这个号码是你的、当前已被分配,或者能收消息。libphonenumber 自己的 FAQ 就提醒过:不要把格式有效当成号码已分配且可被送达的证据。
我的号码打电话没问题,某个服务却不收,为什么?
各家服务会在格式之上套用自己的政策,而这些和号码是否格式良好是两回事。政策只是「一个在别处被接受的号码在这里被拒」的若干可能原因之一,它并不是对每一处这种差别的诊断。请读这个服务给出的那条具体提示,因为其中有些提示区分的是相当不同的情况。
我号码填错了却被接受了,现在怎么办?
在服务要求填号码的地方把它改掉——如果当前流程提供这个机会就在流程里改,如果你进得去账号就在账号设置里改——然后重新发起一次发送。如果这个服务不让你改号码,除非先通过一项你通不过的检查,那这件事就从格式问题变成了这个服务的账号找回问题。
