AIOHTTP 将 %3A 替换为:

AIOHTTP replacing %3A with :

此问题的修复:

import yarl
async with cs.get(yarl.URL(f"https://ipqualityscore.com/api/json/url/{self.token}/{url}",encoded=True)) as r:

你好,我遇到了 AIOHTTP 将 %3A 等字符转换为原始 : 的问题。我需要在 API 请求中使用 %3A 版本,如果不是,它会引发 404

My code:

for link in results:
    url = urllib.parse.quote(link, safe = '')
    await ctx.send(url)
    ## ^^ 1st ^^

    async with aiohttp.ClientSession() as cs:

        await ctx.send(f"https://ipqualityscore.com/api/json/url/{self.token}/{url}")
        ## ^^ 2nd ^^

        async with cs.get(f"https://ipqualityscore.com/api/json/url/{self.token}/{url}") as r:
            text = await r.json()
            await ctx.send(text)

URL it should've used:

https://ipqualityscore.com/api/json/url/PRIVATE_TOKEN/https%3A%2F%2Fstreancommunuty.ru%2Ftradoffer%2Fnew%2F%3Fpartner%3D1284276379%26token%3DiMDdLkoe

error raised (and url used):

aiohttp.client_exceptions.ContentTypeError: 0, message='Attempt to decode JSON with unexpected mimetype: text/html; charset=utf-8', url=URL('https://ipqualityscore.com/api/json/url/PRIVATE_TOKEN/https:%2F%2Fstreancommunuty.ru%2Ftradoffer%2Fnew%2F%3Fpartner=1284276379&token=iMDdLkoe')

更多 explaining/highlighting 作为图像时出错

编辑:

基于@Weeble 回答的最少工作代码。

它使用 yarlencoded=True 停止重新引用 %3A:

import urllib.parse
import aiohttp
import asyncio
import yarl

import os
token = os.getenv('IPQUALITYSCORE_TOKEN')

link = 'https://streancommunuty.ru/tradoffer/new/?partner=1284276379&token=iMDdLkoe'

async def main(link):
    url = urllib.parse.quote(link, safe='')
    print('--- url ---')
    print(url)
    
    async with aiohttp.ClientSession() as cs:
        
        yarl_url = yarl.URL(f"https://ipqualityscore.com/api/json/url/{token}/{url}", encoded=True)
                            
        async with cs.get(yarl_url) as r:
            #print('--- text ---')
            #text = await r.text() 
            #print(text)
            print('--- data ---')
            data = await r.json()
            print(data)
            print('--- url ---')
            print(r.url)
            
loop = asyncio.get_event_loop()
loop.run_until_complete(main(link))

编辑:

我发现 Request url of client session gets malformed #3424 这表明它使用模块 yarl` 自动重新引用一些字符。这样做是为了帮助创建正确的 URL,但在您的情况下,这只会造成问题。它可能需要更改源代码才能停止它。

以下是不能解决所有问题的旧版本。


OLD:(没有解决主要问题)

如果我引用 link 两次,代码不会引发错误

url = urllib.parse.quote(link, safe='')  # first time
url = urllib.parse.quote(url)            # second time

但我没有 TOKEN,所以我从服务器收到消息 Invalid or unauthorized key,我无法检查这是否解决了所有问题。


用于测试的最少工作代码。

import urllib.parse
import aiohttp
import asyncio

token = 'PRIVATE_TOKEN'
link = 'https://streancommunuty.ru/tradoffer/new/?partner=1284276379&token=iMDdLkoe'

async def main(link):
    url = urllib.parse.quote(link, safe='')
    url = urllib.parse.quote(url)
    print('--- url ---')
    print(url)
    
    async with aiohttp.ClientSession() as cs:
    
        async with cs.get(f"https://ipqualityscore.com/api/json/url/{token}/{url}") as r:
            #print('--- text ---')
            #text = await r.text()
            #print(text)
            data = await r.json()
            print('--- data ---')
            print(data)
            
loop = asyncio.get_event_loop()
loop.run_until_complete(main(link))

结果:

--- url ---
https%253A%252F%252Fstreancommunuty.ru%252Ftradoffer%252Fnew%252F%253Fpartner%253D1284276379%2526token%253DiMDdLkoe
--- data ---
{'success': False, 'message': 'Invalid or unauthorized key. Please check the API key and try again.', 'request_id': '4DqddqGpINmFBAI'}

首先,你确定这是你想要做的吗?我问是因为虽然 : 是 URLs 中的保留字符,但在 URL 的 path 组件中不用作分隔符,所以不管它是否是百分比编码的,它对网络服务器来说应该意味着完全相同的事情。您确定 : 是否是百分比编码是导致您出现问题的唯一原因吗?也就是说,这个特定的 Web 服务器可能没有正确遵循 RFC,在这种情况下,您可能需要解决它。

如果你想做的,我认为你需要。从这个问题的答案来看,听起来你可以这样做:

import yarl

...

ipqs_url = yarl.URL(
    f"https://ipqualityscore.com/api/json/url/{self.token}/{url}",
    encoded=True)
await ctx.send(ipqs_url)

同样,您可以将 yarl.URL 对象传递给 cs.get。