V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
AnjingJingan
V2EX  ›  Node.js

node.js axios 回调问题

  •  
  •   AnjingJingan · 2021-09-18 09:42:41 +08:00 · 6320 次点击
    这是一个创建于 1167 天前的主题,其中的信息可能已经有所发展或是发生改变。

    浏览器发起请求,后端 node.js 收到浏览器请求后用 axios 请求一个接口,如何把接口的返回结果给浏览器?

    const http = require('http')
    const axios = require('axios')
    const qs = require('qs')
    var request = require('request');
    
    //    返回一个 Server 实例
    const server = http.createServer()
    
    async function getData (){
        let obj = {
            'type': "1"
        }
    
        url = "http://httpbin.org/post"
        const promise = axios.post(url, qs.stringify(obj), {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
            }
        })
    
        const dataPromise = promise.then((response)=>response.data)
        return dataPromise
    }
    
    
    server.on('request', function (request, response) {
    
        console.log('收到客户端的请求了,请求路径是:' + request.url)
    
        response.write('hello')
        getData().then((res) => {
            // response.write(res)
            console.log(res)  //res 怎么返回给前端
        })
        // 告诉客户端,我的话说完了,你可以呈递给用户了
        response.end()
    })
    
    server.listen(3000, function () {
        console.log('服务器启动成功了,http://127.0.0.1:3000/')
    })
    
    13 条回复    2021-11-20 22:28:17 +08:00
    Desmondli
        1
    Desmondli  
       2021-09-18 09:45:19 +08:00   ❤️ 1
    response.end() 放到 getData.then 的回调里边
    imherer
        2
    imherer  
       2021-09-18 09:45:35 +08:00
    浏览器可以直接用 axios,直接在浏览器层面用 axios 请求就好了

    如果你自己想要包装的话,就把你 node.js 里的结果写成一个 api 服务,然后再在浏览器里请求这个 api 拿到结果就好了
    xuxuxu123
        3
    xuxuxu123  
       2021-09-18 09:48:19 +08:00   ❤️ 1
    1 楼是对的;
    或者用 async/await,node 服务端 await getData()之后再返回给浏览器
    cw2k13as
        4
    cw2k13as  
       2021-09-18 10:20:40 +08:00
    我怎么感觉你这个代码我看不明白,async 搭配 then ??? 然后 dataPromise 返回的是一个 promise 啊不是结果啊,response.end()也写错位置了,我感觉你没搞懂 async/await,和 promise
    helim
        5
    helim  
       2021-09-18 10:46:06 +08:00
    我猜你是想把 getData 拿到的数据 response.end()过去给客户端,但是 getData 是个异步,是吧?
    那可以这样写
    async function getData(callback) {
    const res = await axios.post(url)
    callback(res)
    }
    server.on('request', function (request, response) {
    getData(res => {
    response.end(res)
    })
    })

    既然用了 async await 就没啥必要用其他复杂的用法
    helim
        6
    helim  
       2021-09-18 10:47:48 +08:00
    3L 说的也对,但是你需要要把 function (request, response)改为 async 函数
    都可以
    libook
        7
    libook  
       2021-09-18 11:26:02 +08:00   ❤️ 1
    回复没法格式化代码,你自己贴到编辑器里格式化一下吧。

    ```
    const http = require('http');

    const server = http.createServer((request, response) => {
    console.log('收到浏览器请求流。');

    // 构造发出请求的 URL
    const url = new URL('http://httpbin.org/post');
    // 添加 Search,也就是 Query string
    url.search = new URLSearchParams({
    'type': "1",
    });

    // 向 httpbin 发送请求流
    const req = http.request(
    url,
    {
    "method": "POST",
    "headers": {
    "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
    },
    },
    res => {
    console.log('收到了 httpbin 返回流');

    console.log('将 httpbin 返回流对接到浏览器的返回流。');
    res.pipe(response);
    },
    );

    // 结束 httpbin 请求流
    req.end();
    });

    server.listen(3000);
    ```

    题主这个需求有很多种方式可以实现,最简单的是流( Stream )。

    浏览器向这个 node 服务发送请求的时候,node 服务会接收到一个来自浏览器的请求流,然后 node 服务向 httpbin 发送一个请求流,httpbin 返回一个返回流,然后像接水管管道一样把 httpbin 的返回流接在 node 服务即将返回给浏览器的返回流,浏览器最终收到了数据。

    用流的好处就是不需要自己重建返回给浏览器的返回结构,直接复用上游的返回结构;另一方面 node 服务不需要缓存 httpbin 的整个返回数据,用 async/await 的方案通常会把 httpbin 返回的数据整个存在 node 服务的内存里,小量数据还好,如果是下载大文件的话有撑爆内存的风险。

    http 模块的文档在这:
    https://nodejs.org/api/http.html

    http.createServer 里的回调函数的两个参数类型:
    https://nodejs.org/api/http.html#http_class_http_incomingmessage
    https://nodejs.org/api/http.html#http_class_http_serverresponse

    你可以看到这两个类型都是“Extends: <Stream>”即继承自 Stream,Stream 的文档在这里:
    https://nodejs.org/api/stream.html

    node 服务返回给浏览器,以及 node 服务发请求给 httpbin,都是属于可写流( Writable Stream ),可写流在写完之后必须调用 end 来结束流。
    httpbin 返回给 node 服务的流是可读流( Readable Stream ),你可以把可读流用管道方法( pipe )对接到一个可写流上。
    duan602728596
        8
    duan602728596  
       2021-09-18 11:28:38 +08:00
    哪有这么麻烦?
    async function getData() {
    const res = await axios.post();
    return res.data;
    }

    server.on('request', async function (req, res) {
    const data = await getData();

    res.write(data);
    res.end();
    })
    AnjingJingan
        9
    AnjingJingan  
    OP
       2021-09-18 11:57:24 +08:00
    @cw2k13as 对,前面用 async/await 试过没实现,没改全
    AnjingJingan
        10
    AnjingJingan  
    OP
       2021-09-18 17:37:17 +08:00
    @libook 感谢
    WooodHead
        11
    WooodHead  
       2021-11-03 09:52:52 +08:00
    你这个听起来就像是个代理服务,把整个请求转发给另一个地址,我这几天正好做了这个,可以看看这个库: https://www.npmjs.com/package/http-proxy-middleware ,在这里找找例子: https://codexp.io/npm/1/http-proxy-middleware,express,axios,qs
    WooodHead
        12
    WooodHead  
       2021-11-03 09:54:26 +08:00
    我做的是把请求转给 elasticsearch ,用的是这个例子: https://github.com/appbaseio-apps/reactivesearch-proxy-server/blob/master/index.js
    Dotennin
        13
    Dotennin  
       2021-11-20 22:28:17 +08:00
    想知道 V2EX 不支持 markdown 语法吗, 看着那么留言里写代码都是没有高亮和 index 的贼难受.😣
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1336 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:46 · PVG 01:46 · LAX 09:46 · JFK 12:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.