zoukankan      html  css  js  c++  java
  • 记一次 node-fetch 使用时踩的坑

    记一次 node-fetch 使用时踩的坑

    背景

    在使用如下代码发起请求的时候,个别接口出现了无法得到结果的情况。

    async function req() {
    	const res = fetch(xxx);
    
    	let resData = null;
    	try {
    		resData = await res.clone().json();
    	} catch (err) {}
    
    	if (!resData) {
    		log(await res.clone().text());
    	}
    }
    

    追查

    首先

    我通过其他请求工具,发现出问题的接口是正常响应的。也就是确认了问题是出在自己的代码里面的。

    然后

    我在 try 后面打断点,想看一下 resData 收到的是什么,发现程序根本走不到那,但是 try 里面也没有报错。
    到这一步,我就觉得问题有点奇怪了。

    接下来

    我只能到 node-fetch 的代码里面去加断点看一下是什么情况了。

    在这过程中又出现了很诡异的一幕。我分别在 on('data')on('end') 的时候加调试信息,发现 end 事件没有触发,但如果在 on('data') 中添加断点的话,end 能够触发,而整个请求也能收到响应结果了。

    通过进一步调试,我发现如果不对 node stream 的模型做一个系统的了解,我可能会很难查出问题的原因。但对于问题的解决,依稀记得之前使用 res.json() 的时候是没有问题的。

    尝试解决

    于是,我尝试着将 res.clone().json() 改成 res.json(),果然问题不在出现,请求顺利接收。这时候我开始怀疑是不是 node-fetch 在 clone 的实现上有 bug 。但看了看源码,思路很清晰,感觉不出哪有问题啊。所以,没有了解清楚 stream 相关的思路前,还不能妄下定论。

    而对于 .json 失败后,需要记录响应文本的情况,就改用 res._convert().toString() 实现了。

    原因探究

    后来,我又通过一步一步断点调试和对 stream 的文档和源码的查看,终于定位了问题。

    原来,node-fetch 在 clone 的时候产生了两个目标,源码如下:

    p1 = new PassThrough();
    p2 = new PassThrough();
    body.pipe(p1);
    body.pipe(p2);
    // set instance body to teed body and return the other teed body
    instance.body = p1;
    body = p2;
    

    然后我的代码使用了其中一个即 res.clone 的返回进行 .json 操作,相当于 p2.json()。但对另一个 res 即 p1 没有做处理。
    而 stream 有一个 back pressure 机制,因为 p1 没有消耗,缓存数据满时会使其源 pause,从而导致 p2 也不能结束。

    结语

    • 使用 stream 时,若 pipe 了多个目标,一定要注意他们相互之间的影响。
    • 对于一项技术,唯有在透彻理解其机制后,才能更好的运用。
  • 相关阅读:
    C Python类型互换
    C、C++中如何成功嵌入python
    常见Style 对象属性值
    转: , , 的区别
    dom4j: 用dom4j生成xml后第二行空行的问题
    dom4j: 生成的XML文件根节点 xmlns="" 的问题
    android
    android studio
    android studio
    FFmpeg编译: undefined reference to 'av_frame_alloc()'
  • 原文地址:https://www.cnblogs.com/snadn/p/6524864.html
Copyright © 2011-2022 走看看