【问题标题】:NodeJS passing POST to external API using POSTNodeJS 使用 POST 将 POST 传递给外部 API
【发布时间】:2020-04-01 11:22:16
【问题描述】:

遇到可怕的 JSON 错误。

我正在使用一个据称需要 POST 来将用户添加到组的外部 API。 在我的 nodeJS express 应用程序中 - 我想将来自我的应用程序的数据传递给外部 API。

我的“GET”方法有效 - 但现在我正在尝试将表单提交给我的应用,并使用“POST”将数据传递给外部 API。

这是我正在测试的代码(假设 api url 和凭据是正确的 - 而不是问题) 我已经测试了使用 Postman 将相同的 JSON 对象直接传递给外部 API 的外部 API,并且它可以正常工作。

const express = require('express');
const router = express.Router();
const https = require('https');


    function callExternalAPI( RequestOptions ) {
        return new Promise((resolve, reject) => {
            https.request(
                RequestOptions,
                function(response) {
                    const { statusCode } = response;
                    if (statusCode >= 300) {
                        reject(
                            new Error( response.statusMessage )
                        );
                    }

                    const chunks = [];

                    response.on('data', (chunk) => {
                        chunks.push(chunk);
                    });

                    response.on('end', () => {
                        const result = Buffer.concat(chunks).toString();
                        resolve( JSON.parse(result) );
                    });

                }
            )
            .end();
        })
    }


    router.get('/thing', /*auth,*/ ( req, res, next ) => {

        callExternalAPI(
            {
                host: 'api_url',
                path: '/list',
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Basic ' + new Buffer( auth_un + ':' + auth_pw ).toString('base64')
                }
            }
        )
        .then(
            response => {
                console.log(response);
            }
        )
        .catch(
            error => {
                console.log(error);             
            }
        );

    });


    router.post('/thing', /*auth,*/ ( req, res, next ) => {

        callExternalAPI(
            {
                host: 'api_url',
                path: '/addThing',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Basic ' + new Buffer( auth_un + ':' + auth_pw ).toString('base64')
                },
                data: {
                    'group_id': req.body.group_id,
                    'person_id': req.body.person_id
                }
            }
        )
        .then(
            response => {
                console.log(response);
            }
        )
        .catch(
            error => {
                console.log(error);             
            }
        );

    });

module.exports = router;

控制台记录 req.body 看起来是这样的

{ group_id: '45b62b61-62fa-4684-a058-db3ef284f699',  person_id: '3b1c915c-3906-42cf-8084-f9a25179d6b2' }

错误看起来像这样

undefined:1
<html><title>JSpring Application Exception</title>
<h2>JSpring Exception Stack Trace</h2>
<pre>SafeException: FiberServer.parsers.parseJSONBuf(): JSON parse failed.
^    
SyntaxError: Unexpected token < in JSON at position 0

授予 req.body 的 console.log 没有所需的双引号,但我认为这只是日志转储格式 - 但它可能正在修改 JSON。我尝试将其包装在 stringify 中;意思是这样的: data: JSON.stringify( req.body ) (但会发生同样的错误)。

callExternalAPI(
            {
                host: 'api_url',
                path: '/addThing',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Basic ' + new Buffer( auth_un + ':' + auth_pw ).toString('base64')
                },
                **data: JSON.stringify( req.body )**
            }
        )

我正在邮递员中对此进行测试,正文为“原始 json”,标题为“应用程序/json” 身体是这样的:

{
    "group_id": "45b62b61-62fa-4684-a058-db3ef284f699", 
    "person_id": "3b1c915c-3906-42cf-8084-f9a25179d6b2"
}

【问题讨论】:

    标签: javascript node.js https


    【解决方案1】:

    您应该尝试在请求正文中write POST 有效负载,而不是在选项对象中传递它:

    function callExternalAPI( RequestOptions ) {
      const { data, ...options } = RequestOptions;
      return new Promise((resolve, reject) => {
        const req = https.request(
          options,
          function(response) {
            const { statusCode } = response;
            if (statusCode >= 300) {
              reject(
                new Error( response.statusMessage )
              );
            }
    
            const chunks = [];
    
            response.on('data', (chunk) => {
              chunks.push(chunk);
            });
    
            response.on('end', () => {
              const result = Buffer.concat(chunks).toString();
              resolve( JSON.parse(result) );
            });
    
          }
        );
        req.write(JSON.stringify(data));
        req.end();
      })
    }
    

    【讨论】:

    • 好的,但我如何将它传递给 callExternalAPI()?加 - 只需添加写入,中断对同一函数的“获取”调用
    • 从问题中可以看出,您已经将它作为 RequestOptions 的一部分(data 属性)传递。因此,您可以尝试简单地破坏data(POST 有效负载)上的RequestOptions 和其余选项。 const { data, ...options } = RequestOptions;
    • @jpmyob 我错过了其余选项的扩展运算符,对不起,更新了答案
    • 我明白你在做什么——但我得到了错误,它破坏了“get”调用。如果它有效,我不介意为 POST 与 GET 编写单独的函数,但我收到此错误...TypeError [ERR_INVALID_ARG_TYPE]:第一个参数必须是字符串或缓冲区类型之一。接收到的类型对象(使用你的函数)
    • @jpmyob 我认为发生新错误是因为我们在将data 对象传递给req.write 之前没有对其进行字符串化。所以req.write(JSON.stringify(data)); 应该修复它,更新答案。
    【解决方案2】:

    在快递中你必须使用 bodyParser 在初始化快速应用程序时在文件顶部添加以下行

    const app = express()
    const bodyParser = require('body-parser')
    app.use(bodyParser.urlencoded({ extended: false }))
    app.use(bodyParser.json())
    

    https://medium.com/@adamzerner/how-bodyparser-works-247897a93b90

    【讨论】:

    • 这是一个路由控制器,在主app.js中使用body parse...
    猜你喜欢
    • 1970-01-01
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多