暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

URL编码

生有可恋 2023-02-09
1522

我们经常会被网址中的%以及各种不明含义的字符搞迷糊,不明白这些字符代表的是什么意思,比如以下链接:

    http://etop.com/WebReport/ReportServer?reportlet=fine/it/%E7%A7%91%E5%AE%A4%E7%94%B5%E8%AF%9D.cpt
    复制

    在URL后面一段以%开头的字符串,它代表什么意思?

      %E7%A7%91%E5%AE%A4%E7%94%B5%E8%AF%9D
      复制

      它实际上是一串中文的编码,使用的是utf-8编码,一个中文字符用utf-8编码需要3个字节,每字节的编码前用%隔开。所以将上述编码进行decode,可以看到真实的中文字符。

      我们使用 python 来演示这个过程:

        >>> b'\xE7\xA7\x91'.decode('utf-8')
        '科'
        >>> v = b'\xE7\xA7\x91\xE5\xAE\xA4\xE7\x94\xB5\xE8\xAF\x9D'
        >>> v.decode('utf-8')
        '科室电话'
        复制

        在 python 中16进制数用 \x 表示,三个字节表示一个中文字符。对二进制进解码后可以生成utf-8编码的字符串,同样字符串也可以编码成utf-8的二进制表示。

        以上有点绕,实际上'E7A791'就是utf-8的实际编码,通过解码可以得到中文字符。那为什么URL中不能含中文呢?不是域名都可以是中文的吗,比如新华网.cn

        首先中文域名用的并不多,以新华网为例,它的页面上的其它链接全都是英文链接,只有首页是中文域名。其次 URL 要怎么表示是有规范的,它的规范就要求只能用英文,不能用其它特殊字符,包括中文或其它国家的字符。

        但我们平时在浏览器中可以看到中文,难道我们看错了?比如以下截图:

        URL中的中文只是停留在页面显示上,如果我们把URL拷贝并粘贴到写字板里,就会发现它变成带%的编码了。

        我们从原理出发,URL实际上会被两个程序用到,一个是浏览器即客户端服务,另一个服务器端,即http服务器。它们之间是用http协议在通讯,其中浏览器向web服务器发起http请求,而这个请求的包头就含URL。

        我们通过浏览器自带的开发者工具查看 http request 的 header,即标头。在浏览器上敲F12进入到开发者工具,查看“网络”标签下的标头:

        虽然浏览器的地址栏里显示的是中文,但在浏览器发起的请求中还是将中文字符做了编码,这里使用的是utf-8编码。不同的浏览器所使用的编码不一定一样 ,这是浏览器的个人行为,并不是行业标准。因为很多软件都可以发起http请求,比如 curl 工具,python 的 requests 库。

        浏览器发出 http 请求了,服务端还要接受。如果服务端不知道你发来的是什么编码,那么就会报错。比如 tomcat 在接受中文编码的 URL 时,有可能会就报错:

        这里就是 tomcat 的配置没有指定默认的编码,当接受到来自浏览器的utf-8的URL请求时就会解析错误,显示乱码。此时调整 tomcat 的 conf/server.xml   即可支持 utf-8 编码的请求。

          <Connector port="80" protocol="HTTP/1.1"
          connectionTimeout="20000"
          redirectPort="8443"
          minSpareThreads="50"
          enableLookups="false"
          URIEncoding="UTF-8"
          />
          复制

          增加了一行 URIEncoding="UTF-8",让服务端接受 utf-8 编码的请求。

          因为最终的服务端的处理过程是由服务端程序来处理,所以当URL编码中出现无法理解的部分有可能是服务端程序自己在处理编解码,而非标准流程。比如以下编码:

            fine%2Fit%2F%5B79d1%5D%5B5ba4%5D%5B7535%5D%5B8bdd%5D.cpt
            复制

            从结构上看它还是一个以%分隔的编码格式,这个编码过程实际上是通过 javascript进行编码的,它有4个函数来处理编解码:

              encodeURI()
              encodeURIComponent()
              decodeURI()
              decodeURIComponent()
              复制

              我们在 node.js 中对其进行验证:

              最终通过 javascript 解码后的字符串为:

                fine/it/[79d1][5ba4][7535][8bdd].cpt
                复制

                它实际上并不是一个正常的字符串,因为被[ ] 括起来的部分还是编码。但这个编码是由服务端自己解析,并不是标准的URL编码。这一串编码实际用于帆软的报表,它自己会对其进行编解码。

                它的编码过程大概如下:

                  s = 'fine/it/科室电话.cpt'
                  function cjkEncode(text) {
                  if (text == null) {
                  return "";
                  }
                  var newText = "";
                  for (var i = 0; i < text.length; i++) {
                  var code = text.charCodeAt(i);
                  if (code >= 128 || code == 91 || code == 93) {//91 is "[", 93 is "]".
                  newText += "[" + code.toString(16) + "]";
                  } else {
                  newText += text.charAt(i);
                  }
                  }
                  return newText;
                  }


                  console.log(cjkEncode(s))
                  复制

                   从输出看,其编码出来的URL,与我们通过 javascript 解码出来的一样:

                  而这个方括号中间的内容实际上是unicode,我们在 python 可以验证:

                    >>> s = '\u79d1\u5ba4\u7535\u8bdd'
                    >>> s
                    '科室电话'
                    >>>
                    复制

                    最后做一下总结:

                    URL中的中文编码是通过javascript的两个encode函数生成的,它们的特点就是以%分隔。这两个函数 encodeURI(),encodeURIComponent() 在使用上有点小差异,主要体现在是否对 进行编码。但编码后的 URL 都能通过解码函数还原。

                    如果URL中还含有其它不明含义的编码,比如帆软的 [xxxx] 中间以 unicode 编码的字符串,这个是它自家的编解码,不是标准流程,由它自家的后台程序解析,当然如果了解它的含义后也可以自己写函数解析。

                    浏览器中的中文只是显示为中文,在后台 http 请求中还是以编码后的为准,可以通过抓包来查看 http 的请求包的包头来查真实的URL。

                    目前业界的标准URL编码规范是使用 javascript 的那两函数来编码,其它语言也有支持,可以理解为是一种行业规范。早期的浏览器对URL中文的编码比较混乱,目前现代浏览器都是使用 javascript 的那一套,以 % 分隔很好识别,%后面接的是编码,一般是 utf-8 编码,当然也支持其它编码,但需要服务器端解析时支持。

                    参考

                      # 如何查 http 头
                      https://blog.csdn.net/jiang7701037/article/details/94741670
                      # python 对 URL 的编码
                      https://blog.csdn.net/u014663232/article/details/103501574
                      # tomcat 中文 URL
                      https://blog.51cto.com/u_15338211/3561247
                      # javascript url编码函数用法
                      https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent
                      # 阮一峰 《关于URL编码》
                      https://www.ruanyifeng.com/blog/2010/02/url_encoding.html
                      复制

                      全文完。

                      如果转发本文,文末务必注明:“转自微信公众号:生有可恋”。

                      文章转载自生有可恋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论