首页 > 解决方案 > python urllib.parse.urljoin 在以数字和冒号开头的路径上

问题描述

对不起,什么鬼?

>>> import urllib.parse
>>> base = 'http://example.com'
>>> urllib.parse.urljoin(base, 'abc:123')
'http://example.com/abc:123'
>>> urllib.parse.urljoin(base, '123:abc')
'123:abc'
>>> urllib.parse.urljoin(base + '/', './123:abc')
'http://example.com/123:abc'

python3.7文档说:

在 3.5 版更改:更新行为以匹配 RFC 3986 中定义的语义。

该 RFC 的哪一部分强制执行了这种疯狂,是否应该将其视为错误?

标签: pythonurlurllib

解决方案


该 RFC 的哪一部分强制执行这种疯狂?

如RFC3986所示,此行为是正确的并且与其他实现一致

包含冒号字符(例如,“this:that”)的路径段不能用作相对路径引用的第一段,因为它会被误认为是方案名称。这样的段之前必须有一个点段(例如,“./this:that”)以进行相对路径引用。

已经在另一篇文章中讨论

URI 路径中允许使用冒号。但是在使用冒号编写相对 URI 路径时需要小心,因为这样使用是不允许的:

<a href="tag:sample">

在这种情况下,标签将被解释为 URI 的方案。相反,您需要像这样编写它:

<a href="./tag:sample">

的使用urljoin

该函数urljoin只是将两个参数都视为 URL(没有任何假设)。它要求它们的方案相同或第二个方案来表示相对 URI 路径。否则,它只返回第二个参数(尽管恕我直言,它应该引发错误)。通过查看urljoin的来源,您可以更好地理解逻辑。

def urljoin(base, url, allow_fragments=True):
    """Join a base URL and a possibly relative URL to form an absolute
    interpretation of the latter."""
    ...
    bscheme, bnetloc, bpath, bparams, bquery, bfragment = \
            urlparse(base, '', allow_fragments)
    scheme, netloc, path, params, query, fragment = \
            urlparse(url, bscheme, allow_fragments)

    if scheme != bscheme or scheme not in uses_relative:
        return _coerce_result(url)

解析器例程的结果urlparse如下:

>>> from urllib.parse import urlparse
>>> urlparse('123:abc')
ParseResult(scheme='123', netloc='', path='abc', params='', query='', fragment='')
>>> urlparse('abc:123')
ParseResult(scheme='', netloc='', path='abc:123', params='', query='', fragment='')
>>> urlparse('abc:a123')
ParseResult(scheme='abc', netloc='', path='a123', params='', query='', fragment='')

推荐阅读