zoukankan      html  css  js  c++  java
  • request 请求大数精度丢失问题

    背景

    • BFF Client 使用的 npm 包 request-promise-native 请求微服务接口返回 ID 精度丢失
      > 1713166949059674112 => 1713166949059674000

    为什么会丢失?

    • 存储二进制时小数点的偏移量最大为52位,计算机存储的为二进制,而能存储的二进制为62位,超出就会有舍入操作,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即9007199254740992大于 9007199254740992 的可能会丢失精度
    • request-promise-native 发起请求时,当options.json 不为 false 会使用 JSON.parse 解析 body
    if (self._json) {
      try {
        response.body = JSON.parse(response.body, self._jsonReviver)
      } catch (e) {
        debug('invalid JSON received', self.uri.href)
      }
    }
    

    最小 demo

    搭建服务 API

        public long getId() {
            return id + 1713166949059674112L;
        }
    
    * 修改 controller 层添加 post 请求
    
        @PostMapping("/greeting_create")
        public Greeting createGreeting(@RequestParam(value = "name", defaultValue = "World") String name) {
            return new Greeting(counter.incrementAndGet(), String.format(template, name));
        }
    
    • 请求
      • GET 请求: curl http://localhost:8080/greeting
      • POST 请求:curl -X POST http://localhost:8080/greeting_create
    {"id":1713166949059674120,"content":"Hello, World!"}
    

    解决方案

    1. 获取响应体的字符串,使用 JSONbigid 转化成字符串

    • 优点:只影响当前请求
    • 缺点:不支持 POST 请求方式,

      • 通过 json 传参数不支持
      • 通过 form + json: false 传参数需要后端接口支持
    • GET 请求

    const rp = require('request-promise-native');
    const jsonBigInt = require('json-bigint');
    
      const getOptions = {
        'method': 'GET',
        json: false,
        'url': 'http://localhost:8080/greeting',
      };
    
      const getRes = await rp(getOptions);
      console.log('get result: ', jsonBigInt.parse(getRes));
    
    • POST 请求:不支持,json 被占用,一定会执行 JSON.parse
    const rp = require('request-promise-native');
    const jsonBigInt = require('json-bigint');
    
      const postOptions = {
        'method': 'POST',
        'url': 'http://localhost:8080/greeting_create',
        json: { name: 'cassTime' },
      };
      const postRes = await rp(postOptions);
      console.log('post result: ', jsonBigInt.parse(postRes));
    

    2. 使用 JSONbig.parse() 替换 JSON.parse()

    • 优点:实现简单,支持 POST
    • 缺点:影响所有的 JSON.parse() 解析
    const rp = require('request-promise-native');
    const jsonBigInt = require('json-bigint');
    
    async function jsonBigReplaceParse() {
      const oldParse = JSON.parse;
      JSON.parse = jsonBigInt.parse;
      const postOptions = {
        'method': 'POST',
        'url': 'http://localhost:8080/greeting_create',
        json: { name: 'cassTime' },
      };
      const postRes = await rp(postOptions);
      console.log('post result: ', postRes);
      JSON.parse = oldParse;
    }
    
  • 相关阅读:
    uva624 CD (01背包+路径的输出)
    算法:全排列
    Android使用Intent实现拨打电话的动作
    Java并发编程从入门到精通 张振华.Jack --我的书
    《算法导论》— Chapter 12 二叉查找树
    Java中arraylist和linkedlist源代码分析与性能比較
    Cg入门14:Vertex Shader
    Nucleus PLUS的启动、执行线程和中断处理
    Unity Shaders and Effects Cookbook (3-5) 金属软高光
    EasyDarwin开发出相似于美拍、秒拍的短视频拍摄SDK:EasyVideoRecorder
  • 原文地址:https://www.cnblogs.com/xulonglong/p/request-qing-qiu-da-shu-jing-du-diu-shi-wen-ti.html
Copyright © 2011-2022 走看看