我正在尝试将我的Wi-Fi SSID更改为表情符号,但web UI不允许它。相反,我将有效的PUT请求捕获到路由器的API,使用Chrome的开发工具将其复制为fetch呼叫,将SSID更改为表情符号,然后重播请求。它很棒。

但是,当我尝试使用Python请求时,它会将表情符号(????)转义为相应的JavaScript转义:\uD83E\uDD20。当它被发送到路由器时,它会以某种方式转换为>(大于符号后跟一个空格)。这是令人沮丧的,因为我假设两种方法都会以相同的方式编码表情符号。

由于它适用于JavaScript的fetch,因此消息或表情符号的编码方式必须有所不同。

获取调用:(即使在使用Dev Tools检查请求时,表情符号也会显示为表情符号)(为简洁起见,编辑)

fetch("https://192.168.1.1/api/wireless", {
    "credentials": "omit",
    "headers": {
        "accept": "application/json, text/plain, */*",
        "content-type": "application/json;charset=UTF-8",
        "x-xsrf-token": "[The token for this login session]"
    },
    "referrer": "https://192.168.1.1/",
    "referrerPolicy": "no-referrer-when-downgrade",
    "body": "{
        \"wifi\": [{
            \"boring key 1\": \"boring value\",
            \"boring key 2\": \"boring value\",
            \"ssid\": \"????\",
            \"boring key 3\": \"boring value\",
            \"boring key 4\": \"boring value\"
        }]
    }",
    "method": "PUT",
    "mode": "cors"
});

请求电话:(为简洁而编辑)

res = session.put('https://192.168.1.1/api/wireless', 
                   verify=False, 
                   json={
                       "wifi":[{
                           "boring key 1":"boring value",
                           "boring key 2":"boring value",
                           "ssid":"????",
                           "boring key 3":
                           "boring value",
                           "boring key 4":"boring value"
                       }]
                   })

那么他们被编码的方式有什么不同?我怎样才能看到fetch的实际输出是什么? (Dev Tools只显示一个表情符号,没有转义序列。)

分析解答

requests library中的json参数完成的默认JSON处理基本上将ensure_ascii设为True,以便提供这种类型的编码形式。基本上,put调用将作为以下内容发送到服务器:

PUT / HTTP/1.1
Host: 192.168.1.1
User-Agent: python-requests/2.21.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 24
Content-Type: application/json

{"demo": "\ud83e\udd20"}

这不是你想要的。为了做你想做的事,你必须手动编码JSON并明确提供标题,如下所示:

requests.put(
    'https://192.168.1.1',
    data=json.dumps({"demo": "????"}, ensure_ascii=False).encode('utf8'),
    headers={'Content-Type': 'application/json'},
)