http GET 请求 URL 总结

URL 只能使用英文字母、阿拉伯数字和某些标点符号,不能使用其他文字和符号。网络标准RFC 1738做了硬性规定:

“…Only alphanumerics [0-9a-zA-Z], the special characters “$-_.+!*’(),” [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”

“只有字母和数字[0-9a-zA-Z]、一些特殊符号”$-_.+!*’(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。”

为什么需要 URL 编码

秉承着「知其然还要知其所以然的态度」,先来思考下什么情况下,我们需要编码?

  • 这是隐私数据,不是适合明文传输
  • 编码后可以有效的压缩传输的数据量
  • 包含某些会引起歧义的字符

在 URL 中之所以要编码,就是因为在传输的内容跟预留字符(&、=、?)有相同的时候,会造成 URL 服务器的解析错误,比如参数的 key = value 键值对中,在 value 中包含 &、=、?等几种预留字符的时候,你让服务器如何解析?

哪些字符需要编码

保留字

URL 可以划分成若干组件、协议、主机、路径等。

  • 一些字符用来分隔不同的组件,比如「:/?#@」
  • 一些字符在每个组件中分隔的,比如 & =

不安全字符

还有些字符,当它们直接放在 URL 中时,可能会引起解释程序的歧义

  • 空格——URL 在传输过程中,用户排版时,文本处理程序在处理 URL的过程中,都可能引入无关紧要的空格
  • 引号和<>——通常用于在普通文本中起到分隔 URL 的作用
  • # 用于标示书签或锚点
  • % 本身用作对不安全字符编码时的特殊字符,所以本身需要编码
  • {}[]|^ 某些网关或者传输代理会篡改这些字符

注意

由于历史原因,目前存在一些不标准的编码实现,比如对于符号~ 虽然RFC3986文档规定,对于~不需要编码,但是一些老的网关或者传输代理会。比如[]也被编码了。

对于 URL 中的合法字符,编码和不编码是等价的,但是对于上面提到的那些字符,如果不编码,那它们可能会造成 URL 语义的不同。因此,对于 URL 而言,只有普通英文字符和数字、特殊字符和保留字符,能出现在未经编码的 URL 中,其他字符都需要经过编码。

编码规则

先介绍几种存在的编码规则,详细的内容可以看《字符编码笔记》:

  • ASCII 码: ASCII 码一共规定 128 个字符编码(包括 32 个不能打印的控制符号)
  • 非 ASCII 码:英语 128 个符号编码是够的,但用来表示其他语言,128 个符号是不够的。一些欧洲国家决定利用字节中闲置的最高位编入新的符号,前 128 位是相同的,后面的 128 位不同
  • unicode:将世界上所有的符号都纳入其中,每一个符号都给予一个独一无二的编码,消除乱码问题。Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
  • UTF-8: UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。

如何编码

URL 编码通常被称为百分号编码(URL Encoding, also know as percent-encoding),因为它的编码方式很简单,使用 % 加上两个字符代表一个字节的16进制形式:

URL 编码默认使用的字符集是 ASCII

  • a 在 ASCII 中对应的字节是 0x61,经过 URL 编码后得到就是 %61
  • @ 在 ASCII 中对应的字节是 0x40,经过 URL 编码后得到就是 %40
  • 对于非 ASCII 字符,需要使用 ASCII 字符集的超集进行编码得到相应的字符,然后再对每个字符执行百分号编码
  • 对于 Unicode 字符,RFC 文档建议使用 UTF-8 对其进行编码得到相应的字节,然后再对每个字节执行百分号编码

GET vs POST

在被问到 http GET 和 POST 的区别的时候,普遍给出的回答可能是:

  • GET 的参数包含在 URL 中,POST 的参数通过 request body 进行传递
  • 在 restful api 规则中, GET 用于从服务器获取指定资源,POST 用于在服务器创建资源;GET 操作是安全的,不管进行多少次操作,资源的状态都不会改变,POST 操作不是安全的,重复发起多次 POST 的请求,会导致服务器创建若干资源。

你真的觉得这么回答就是能拿满分了吗?义务教育不是教育过我们不会的时候要多写点答案,老师还会有个感情分给你,让我们再想想。

  • GET 在浏览器回退的时是无害的,而 POST 会再次提交请求
  • GET 产生的 URL 可以被 Bookmark,而 POST 不可以
  • GET 请求会被浏览器主动 cache,而 POST 不会,除非手动设置
  • GET 请求只能进行 URL 编码(就是上面说的 URL 编码),而 POST 支持多种编码方式
  • GET 请求参数会被完整保留在浏览器的历史记录里,而 POST 中的参数不会被保留
  • GET 请求在URL 中传送的参数是有长度限制的,而 POST 没有
  • 对于参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有
  • GET 比 POST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息

对于能轻松列举以上不同点的同学,是需要奖励大红花的,毕竟笔者也是抄了别人的文章才知道的,不过这还不是最终答案,思考问题更深入一些,它们的底层是不是有什么不一样的地方?

我是谁: GET 和 POST 是什么?

  • HTTP 协议中的两种发送请求的方法

我从哪里来:HTTP 是什么?

  • HTTP 是基于 TCP/IP 的关于数据如何在万维网中通信的协议。
  • GET 和 POST 底层都是 TCP 连接, 能做的事情也是相同的。如果你想给 GET 加上 request body, 给 POST 带上 URL 参数,技术上来说也没什么不行的。

「99%的人都理解错了HTTP中GET与POST的区别」中提出了一个很形象的比喻,在你万维网世界中,将 TCP 比喻成汽车用来运输数据,为了避免送急件的阻塞满载货物的汽车,又提出了交通规则 HTTP 。 HTTP 给汽车运输规定了不同的服务类别,包括 GET、POST、PUT、 DETETE等。浏览器可以想象成运输公司,不同的运输公司对汽车运输货物的量是有要求的,数据量太大对浏览器和服务器都会造成很大负担。

业界不成文的规定是,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。超过的部分,恕不处理。

终极大 boos 来了, GET 和 POST 还有一个很大的不同,简单的说:

  • GET 产生一个 TCP 数据包,POST 产生两个 TCP 数据包。
  • 更容易理解的版本:
    • 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据)
    • 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)

参考资料

  • URL编码
  • 关于URL编码
  • 99%的人都理解错了HTTP中GET与POST的区别
  • golang中使用url encoding遇到的小坑

你可能感兴趣的:(HTTP)