источник
В последнее время при реализации требования необходимо получить доступ к стороннему интерфейсу, сначала вызвать интерфейс A, данные, возвращаемые интерфейсом A, содержат идентификатор задачи, а затем использовать идентификатор задачи для запроса интерфейса B для получения окончательного требуемого данные.
Серверная часть использует узел, поэтому пакет request-promise сначала используется для запроса стороннего интерфейса, однако после получения taskId, возвращаемого интерфейсом A, и вызова интерфейса B ответ интерфейса B на самом деле является системным. ошибка! Простой код выглядит следующим образом
const rp = require('request-promise')
const { taskId } = await rp('https://xxx.com/A')
const options = {
method: 'POST',
uri: 'https://xxx.com/B',
body: {
taskId
},
json: true
}
const result = await rp(options)
// {
// "errorcode": "40001",
// "message": "系统错误",
// "status": "failed"
// }
Затем я использую postman для запроса интерфейса A, получаю новый идентификатор задачи, а затем использую новый идентификатор задачи для запроса интерфейса B, но результат нормальный!
Перепроверив код и убедившись, что запрашиваемые параметры в нормальном формате, я на какое-то время впал в бесконечную медитацию. . .
Находить
Сделав несколько попыток, я обнаружил, что последние две цифры идентификатора задачи, который я получаю с помощью запроса узла, равны 0, т.е.1152921504735848700, и taskId, полученный почтальоном, относительно нормальный.1152921504735848759, затем я делаю следующее в консоли узла
В это мгновение я понял. TaskId в интерфейсе A представляет собой 19-значное число, и когда запрос-обещание разбирает данные в json, 19-значное число теряет свою точность.После проверки данных обнаруживается, что числовой тип js имеет максимум безопасное значение.То есть 2 в 53-й степени (9007199254740992), за пределами этого значения возникнет проблема потери точности. ОрзПолучите правильные данные ответа
Поскольку в начале использовался пакет request-promise, полученный идентификатор задачи потерял свою точность, поэтому вместо этого для отправки запроса использовался собственный http-модуль узла.
const req = https.request('https://xxx.com/A', (res) => {
res.on('data', (chunk) => {
// 由于这里获取到的响应数据是JSON字符串,因此19位的数字只是字符串的一部分,这时获取到的taskId就是正确的数字
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
})
})
Хотя получаются обычные данные ответа, это строка JSON.Далее строку нужно разобрать в JSON, но использование JSON.parse() вызовет проблему потери точности, что очень смущает Орза.
Если этот интерфейс уже управляемый, то 19-значное число можно преобразовать в строку, чтобы не было ошибки при парсинге, но поскольку это сторонний интерфейс, его нельзя изменить. Тогда самое быстрое решение - изменить запрос языка программирования ╮(╯_╰)╭
окончательное решение
В конце концов, я все же использовал node, но использовал более жесткое решение: сначала найти 19-значное число в полученной строке JSON, затем добавить к нему кавычки, а затем использовать JSON.parse(), когда при синтаксическом анализе можно сохранить нормальное значение, чтобы следующий процесс мог проходить естественным образом, код выглядит следующим образом
let result = '{"taskId":1152921504735848759,"status":"CREATED","progress":0.0,"success":true}'
// JSON.parse(result) 不为19位数补上双引号,直接parse时,精度丢失,结果如下:
// {
// taskId: 1152921504735848700,
// status: 'CREATED',
// progress: 0,
// success: true
// }
const taskId = result.match(/[0-9]{19}/)[0] // 正则获取19位数字的值
result = result.replace(taskId,`"${taskId}"`) // 补上双引号
const data = JSON.parse(result)
// {
// taskId: '1152921504735848759', // 解析出来之后是字符串,因此没有丢失精度
// status: 'CREATED',
// progress: 0,
// success: true
// }
Эпилог
Я использую node некоторое время, потому что он не требует вычислений больших чисел, поэтому все числа и идентификаторы хранятся в виде строк, и я никогда не сталкивался с этой проблемой. В этот раз я действительно столкнулся с этим, должен сказать, что js действительно немного слабоват в этом отношении, после этого я также пробовал использовать Go и python для запросов, и все они были правильно обработаны. ┑( ̄Д  ̄)┍ Но узел по-прежнему очень удобен в использовании, ╮(╯▽╰)╭
Thanks!