node.js axios 回调问题

2021-09-18 09:42:41 +08:00
 AnjingJingan

浏览器发起请求,后端 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/')
})
6121 次点击
所在节点    Node.js
13 条回复
Desmondli
2021-09-18 09:45:19 +08:00
response.end() 放到 getData.then 的回调里边
imherer
2021-09-18 09:45:35 +08:00
浏览器可以直接用 axios,直接在浏览器层面用 axios 请求就好了

如果你自己想要包装的话,就把你 node.js 里的结果写成一个 api 服务,然后再在浏览器里请求这个 api 拿到结果就好了
xuxuxu123
2021-09-18 09:48:19 +08:00
1 楼是对的;
或者用 async/await,node 服务端 await getData()之后再返回给浏览器
cw2k13as
2021-09-18 10:20:40 +08:00
我怎么感觉你这个代码我看不明白,async 搭配 then ??? 然后 dataPromise 返回的是一个 promise 啊不是结果啊,response.end()也写错位置了,我感觉你没搞懂 async/await,和 promise
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
2021-09-18 10:47:48 +08:00
3L 说的也对,但是你需要要把 function (request, response)改为 async 函数
都可以
libook
2021-09-18 11:26:02 +08:00
回复没法格式化代码,你自己贴到编辑器里格式化一下吧。

```
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
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
2021-09-18 11:57:24 +08:00
@cw2k13as 对,前面用 async/await 试过没实现,没改全
AnjingJingan
2021-09-18 17:37:17 +08:00
@libook 感谢
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
2021-11-03 09:54:26 +08:00
我做的是把请求转给 elasticsearch ,用的是这个例子: https://github.com/appbaseio-apps/reactivesearch-proxy-server/blob/master/index.js
Dotennin
2021-11-20 22:28:17 +08:00
想知道 V2EX 不支持 markdown 语法吗, 看着那么留言里写代码都是没有高亮和 index 的贼难受.😣

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/802686

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX