URL和URI的知识点

Last Updated: 2023-04-12 00:46:51 Wednesday

-- TOC --

我遇到了一些关于URL和URI的知识点,总结在这篇笔记里面,似乎主要都是URL的问题。

URI和URL的定义

URIUniform Resource Identifier 的缩写,统一资源标识符。简单理解,就是资源ID,独一无二。

URLUniform Resource Locator的缩写,统一资源定位符。简单理解,就是定位一个资源。

可以笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。URL在定义了资源的同时,还包含了获取资源的方式,而URI只有资源ID,可以没有后者。

URL是URI的子集。任何东西,只要能够唯一地标识出来,都可以说这个标识是 URI 。如果这个标识是一个可获取到上述对象的路径,那么同时它也可以是一个 URL ;但如果这个标识不提供获取到对象的路径,那么它就必然不是 URL 。

RFC3986中列举了几种 URI 例子,如下所示:

ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
news:comp.infosystems.www.servers.unix
tel:+1-816-555-1212
telnet://192.0.2.16:80/
urn:oasis:names:specification:docbook:dtd:xml:4.1.2

HTTP协议中,主要使用URI这个词,可能是因为HTTP本身已经说了名获取资源的方式。

区分大小写

其实,不区分大小写的只是域名而已,URL或URI是比域名更长的一个字符串,这个字符串除了域名部分之外,都要区分大小写。

比如,我们去查域名的注册情况,输入小写或者大写,查询结构都是一样的,这表示域名部分大小写不做区分,都一样,是一个域名。

但是域名后面的部分是要区分大小写,最典型的例子是短地址。请看这两个短地址,既有大写也有小写。比如:http://t.cn/R2K9rJI, http://t.cn/R2tu0V3。

可以将URL域名后面的部分理解为磁盘上的文件系统。认识到URL是区分大小写的很重要,因为搜索引擎会将大小写不同的网址作为不同的页面地址来处理,但是网站程序有可能错误地返回了相同页面,这样在搜索引擎看来,是重复内容,轻则去掉索引,重则有可能惩罚整个网站。

链接中的锚也是要区分大小写!(链接中#后面的部分)

URL中的连续/符号

下面这3个网址,是等效的:

http://apache.fayea.com/apr/
http://apache.fayea.com//apr/
http://apache.fayea.com////apr/

URL里面,除了最前面的http[s]://,这里只能有两个/,后面在分段的时候,可以有多个/,效果等同于一个/

其实,这个规则与Linux上的处理文件系统路径的规则一致,请看:

pi@rp02:~ $ cd /home/////pi//////repos
pi@rp02:~/repos $ pwd
/home/pi/repos

注意URL最末尾是否需要/符号

把URL去掉域名部分,剩下的看成Linux的文件夹系统,那么最后是否有 /,表达的含义是不一样的。有 /,表示文件夹,没有 /可能就是一份文件。但是,这个细节如何处理,要根据应用场景来考虑。总之,它们是有区别的。

下面是Flask关于这个细节的一点说明,作为参考:

The following two rules differ in their use of a trailing slash.

@app.route('/projects/')
def projects():
    return 'The projects folder page'

@app.route('/about')
def about():
    return 'The about page'

The canonical URL for the projects endpoint has a trailing slash. It’s similar to a folder in a file system. If you access the URL without a trailing slash (/projects), Flask redirects you to the canonical URL with the trailing slash (/projects/).

The canonical URL for the about endpoint does not have a trailing slash. It’s similar to the pathname of a file. Accessing the URL with a trailing slash (/about/) produces a 404 “Not Found” error. This helps keep URLs unique for these resources, which helps search engines avoid indexing the same page twice.

如果有目录a,访问 /a,Flask(包括Apache Httpd)会自动重定向(301)到 /a/这个链接,然后再返回a目录下的index.html(默认配置)。这个细节很重要,如果你的网站,所有的文件,都是目录下的index.html,要特别留意网页上的链接,是否有 /,如果没有,服务器会处理很多无畏的重定向。

tailing slash规则,对于网站的home page不适用!

英文网站URL的优化

同理,如果是中文网站,在URL必须灵活自定义的情况下,选择使用关键词的拼音。

URL是资产

受欢迎的网页,其URL藏在各大搜索引擎的数据库中,藏在很多用户的收藏夹中,这些URL是资产,它们自带流量。在网站发生变更的时候,记得对它们进行301重定向处理,这是在保护资产。URL应该是最古老的数字资产!他们能够带来现金流......

维持这份数字资产的成本,就是每年的域名和服务器的费用,以及个人投入的时间和精力。

URL Percent Encoding

URL编码通常也被称为百分号编码(percent-encoding),是因为它的编码方式非常简单: 使用%加上两位的字符代表一个字节的十六进制形式。URL编码要做的,就是将每一个非安全的ASCII字符都被替换为%xx格式,对于非ASCII字符,RFC文档建议使用utf-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码。

下面是使用Python标准库的测试代码。

urllib.parse.urlencode的作用是将dict对象转换成Query String

>>> from urllib.parse import urlencode
>>> a = {'a':1,'b':2,'CS笔记':3}
>>> urlencode(a)
'a=1&b=2&CS%E7%AC%94%E8%AE%B0=3'
>>>
>>> b= {'+':1,'a b':2,'@':3}
>>> urlencode(b)
'%2B=1&a+b=2&%40=3'

额....空格编码成了加号?

urllib.parse.quoteunquote可以对普通的string,进行percent-encoding互转:

>>> a = urllib.parse.quote('/a b c d/1 2 3 4')
>>> a
'/a%20b%20c%20d/1%202%203%204'
>>> urllib.parse.unquote(a)
'/a b c d/1 2 3 4'

urllib.parse.urlsplit将一个url分割成5个部分,这5个部分分别是schemenetlocpathqueryfragment,如下:

>>> a = urllib.parse.urlsplit('https://cs.pynote.net/about?a=1&b=2#xyz')
>>> a
SplitResult(scheme='https', netloc='cs.pynote.net', path='/about', query='a=1&b=2', fragment='xyz')
>>> a[0]
'https'
>>> a[1]
'cs.pynote.net'
>>> a[2]
'/about'
>>> a[3]
'a=1&b=2'
>>> a[4]
'xyz'

urllib.parse.urlunsplit刚好反过来,用5个部分来拼出一个url:

>>> urllib.parse.urlunsplit(('https','cs.pynote.net','/about',urllib.parse.urlencode({'a c':1,'b d':2}),'xyz'))
'https://cs.pynote.net/about?a+c=1&b+d=2#xyz'

在URL使用IP地址

比如:

https://192.168.1.2:8080

当使用IPv6地址时,需要用[]将地址括起来,这是为了区分那部分是IPv6地址,那部分是端口号:

https://[X::X]:8080

本文链接:https://cs.pynote.net/net/202109235/

-- EOF --

-- MORE --