V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
raycool
V2EX  ›  Python

求问 aiohttp 和 requests 库,产生的预期不一致。

  •  
  •   raycool · 2022-01-18 19:53:12 +08:00 · 3573 次点击
    这是一个创建于 1038 天前的主题,其中的信息可能已经有所发展或是发生改变。

    币安的批量撤单接口,发送 DELETE 协议,进行批量撤单。
    使用 aiohttp 进行撤单,也就是注释块 1 的那部分代码,直接返回签名无效。
    而使用 requests 进行撤单,也就是注释块 2 的这部分代码,返回订单不存在,因为订单已经不存在了,所以返回订单不存在,符合预期,如果是有效的订单,会直接撤单成功。
    很奇怪的是为什么两个库在 delete 协议有这样的差异,别的 post ,get 请求没问题。

    import requests
    import hmac
    import hashlib
    import time
    import os
    from aiohttp import ClientSession
    import asyncio
    
    api_key = "网站的 apikey"
    secret_key = "网站的 secretkey"
    
    base_url = 'https://fapi.binance.com'
    symbol = "ETHUSDT"
    
    
    def _signature(params):
        params_query_string = urlencode(params)
        return hmac.new(
            secret_key.encode("utf-8"), params_query_string.encode("utf-8"), hashlib.sha256
        ).hexdigest()
    
    
    async def _delete(url, params):
        headers = {"X-MBX-APIKEY": api_key,
                    "Content-Type": "application/x-www-form-urlencoded",
                    "Accept": "application/json"}
        params_encoded = urlencode(params)
        url = url + '?' + params_encoded
    
    
        #1 async with ClientSession() as session:
        #1     async with session.delete(url, headers=headers) as response:
        #1         text = await response.text()
        #1 print('result', text)
    
        #2 response = requests.delete(url, headers=headers)
        #2 print('result', response.json())
    
    
    def run():
        params = {
            "symbol": symbol,
            "origClientOrderIdList": '["aaa-220117222620000008","aaa--220117222620000009"]',  
            "timestamp": int(time.time()*1000)
        }
        params["signature"] = _signature(params)
        url = urljoin(base_url, "/fapi/v1/batchOrders")
        return _delete(url, params)
    
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())
    第 1 条附言  ·  2022-01-19 00:54:15 +08:00

    破案了,确实是两个库对url中有些转义字符处理的规则不一致导致的。
    其中对某种情况下包含特殊转义字符的话
    aiohttp的库的url需要做特别的处理

    from yarl import URL
    async with ClientSession() as session:
        async with session.delete(URL(url, encoded=True), headers=headers) as response:
            text = await response.text()
            print('result', text)
    10 条回复    2022-01-19 11:20:15 +08:00
    ThirdFlame
        1
    ThirdFlame  
       2022-01-18 20:13:17 +08:00
    抓个包 瞅一瞅
    wuwukai007
        2
    wuwukai007  
       2022-01-18 20:15:31 +08:00
    用 tornado 的 tornado.httpclient.AsyncHTTPClient 试试?
    ClericPy
        3
    ClericPy  
       2022-01-18 22:44:58 +08:00
    有现成的 params 参数为啥要手拼 URL...

    土方法: 把 API 地址改成 http://httpbin.org/delete 再发一次看看返回有不一样么
    locoz
        4
    locoz  
       2022-01-18 22:56:46 +08:00 via Android
    还是那句说了一万遍的话:用统一的抓包工具抓个包对比一下,看看两个程序发出去的请求有什么区别
    raycool
        5
    raycool  
    OP
       2022-01-18 23:01:22 +08:00
    @locoz 这会正在用抓包工具测试,很奇葩,mac 下用的 proxyman ,为什么抓不到 aiohttp 的请求,requests 的倒是能抓到。
    raycool
        6
    raycool  
    OP
       2022-01-18 23:02:40 +08:00
    @ClericPy 这个历史遗留问题,刚好币安同时支持 query_string 这种模式, 其他的所有请求都是拼接成 url 来搞的,所以这个也这样写了。
    raycool
        7
    raycool  
    OP
       2022-01-19 00:54:39 +08:00
    @locoz 感谢老哥,终于解决了。
    warcraft1236
        8
    warcraft1236  
       2022-01-19 09:18:39 +08:00
    其实就是 aiohttp 没给你转义?
    bung
        9
    bung  
       2022-01-19 10:11:52 +08:00
    @ClericPy 是正解,不要手拼 URL ,用 params 参数不会出错。
    另外,推荐 httpx ,同步异步都支持的
    raycool
        10
    raycool  
    OP
       2022-01-19 11:20:15 +08:00
    @warcraft1236 转义后的拼接成的 URL ,aiohttp 又给逗号转义回来了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2650 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:32 · PVG 23:32 · LAX 07:32 · JFK 10:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.