下午不知道咋回事就想到了这个状态码,突然好奇有没有人用,就简单了解了一下它的来历,以及思考了一下它的使用场景。
事实上,418甚至都不算是一个HTTP的状态码。它来源于当年的一个愚人节玩笑,所谓的“超文本咖啡壶控制协议”,Hyper Text Coffee Pot Control Protocol。在这个协议里规定了两种错误状态码,一种是406 not acceptable(当然,含义与HTTP的不同),另一种就是这次的418 I’m a teapot,表示服务器是一个茶壶,不能煮咖啡。
这当然是一个玩笑,甚至连这个RFC的内容都是从歌词里引用过来的。原文如下:
The HTCPCP server is a teapot; the resulting entity body may be short and stout.
翻译成中文大概是,服务器是个茶壶,返回实体短又粗。short and stout 是一句歌词。
这当然没法用在正常的HTTP服务器里,除非茶壶是一个嵌入式设备。不过,我还是很慎重地思考了一下这个状态码的非茶壶的使用场景。
I’m a teapot,我是一个茶壶。分析一下这句话的内涵,他想表达什么?是……
- “我是一个茶壶,我啥也不知道,你别找我。”
- “我是一个茶壶,我啥也不知道,你找咖啡壶去。”
- “我是一个茶壶,我不是咖啡壶,不能当咖啡壶用。”
- “我是一个茶壶,我不是咖啡壶,禁止当咖啡壶用。”
- “我是一个茶壶,我不是咖啡壶,咖啡煮坏了你自己负责。”
- “我是一个茶壶,暂时还不能当咖啡壶用。”
- “我是一个茶壶,虽然也能煮咖啡,但由于某些原因暂时不能煮咖啡。”
- ……?
因为我暂时想不到别的,所以8以后的先排除。并且,因为是4开头的状态码,想表达的应该是客户端的错误。然后,我们逐条分析:
-
“我是一个茶壶,我啥也不知道,你别找我。”
用户发起了一个请求,但并不知道服务器是一个茶壶,服务器表示拒绝。
这对应于400 Bad Request,服务器无法理解该请求(或参数错误)。
既然已经有400了,完全没必要加一个418,多此一举。
-
“我是一个茶壶,我啥也不知道,你找咖啡壶去。”
虽然和上一条语义类似,但这一条透露出的一个重要信息是,这个茶壶知道有一个咖啡壶存在。
这其实有点像3xx状态码的重定向,从语义上看,像是308 Permanent Redirect或者303 See Other。但是308更倾向于是对资源URL变化的描述(事实上,我觉得3xx都是对资源的描述),而这个却是对agent变化的描述;至于303就更不沾边了,请求已经被拒绝了,根本谈不上对资源修改后的重定向。
因此,在这个场景下,似乎有其存在价值。因为,别的重定向都是表明同意,或持中立态度,而418可以表明一个拒绝态度的重定向。不过,一个非网关的服务器为什么要知道其他服务器的信息呢?这从设计上来说不是很合适。而且,重定向是否需要具有态度?如果重心在重定向上,为什么不放在3xx里呢?这也是值得商榷的。
-
“我是一个茶壶,我不是咖啡壶,不能当咖啡壶用。”
用户在明知服务器是茶壶的情况下发起了一个请求,茶壶无法处理请求,表示拒绝。
这其实有点复杂。如果用户对茶壶的资源发起了一个咖啡壶特定的请求,那有可能是405 Method Not Allowed;如果用户往茶壶里放了咖啡,茶壶识别不了咖啡,当成了异物,那可能是415 Unsupported Media Type;如果用户直接就没往Accept-*请求头里放茶壶,而是放的咖啡壶,那就类似于406 Not Acceptable了。
无论如何,这是多此一举。
-
“我是一个茶壶,我不是咖啡壶,禁止当咖啡壶用。”
用户在明知服务器是茶壶的情况下发起了一个请求,被服务器严词拒绝。
这有点像403 Forbidden,永久性地拒绝授权。
这也是多此一举。
-
“我是一个茶壶,我不是咖啡壶,咖啡煮坏了你自己负责。”
这相当于是请求已经进了茶壶,但没通过茶壶内部的schema的校验。茶壶发现放进来的是咖啡,就拒绝了这个请求。
这个类似于422 Unprocessable Entity,请求的实体处理不了,因为请求的实体语义不正确(而且在修改请求之前,不应该再次请求)。和3的区别在于,415 是不理解请求的内容是啥,422是理解但不处理。
这也是多此一举。
-
“我是一个茶壶,我不是咖啡壶,果然煮咖啡煮坏了吧。”
这个其实相当于是请求已经成功了,但茶壶在煮咖啡的过程中内部逻辑处理不了,并且报错了。
那这就是经典的500 Internal Server Error,和4xx的语义冲突了。
-
“我是一个茶壶,暂时还不能当咖啡壶用。”
这和情况3不同的地方在于,这是一个暂时的过程,在未来的某一天,这茶壶可能也能煮咖啡了。
这对应于501 Not Implemented,虽然现在还不行,但未来行。
不过这和4xx的语义冲突了。
-
“我是一个茶壶,虽然也能煮咖啡,但由于某些原因暂时不能煮咖啡。”
这相当于茶壶其实可以煮咖啡,但因为自己拉胯了,导致现在煮不了。
这明显是503 Service Unavailable,服务不可用。
不过这也和4xx的语义冲突了。
想来想去,也就只有第三种情况有一定可能,也就是从一个服务器重定向到另一个服务器,而且还不能是对资源的重定向,得是对行为的重定向,还得是个拒绝态度,来来去去我也就想到一个HTTP connect,比如和茶壶connect,茶壶表示你去和咖啡壶connect去;但这就和现在比较主流的RESTful风格(以实体为中心)冲突了。更要命的是,这个状态码的语义相当模糊(至少不是显式声明的语义)。
总而言之,418 I’m a teapot只是一个玩笑,在实际使用中可能没有太大意义。