Node.js调用Stack Exchange API返回原始数据而非JSON的问题排查
解决Stack Exchange API在Node.js中返回乱码的问题
问题背景
我最近碰到个头疼的问题——用Stack Overflow的Search/Advanced API查询问题时,Postman能正常返回JSON数据,但把Postman自动生成的代码放到Node.js应用里调用,却返回一堆乱码原始数据。而且这段代码在其他API上运行都没问题,实在让人困惑。
我用的请求代码是这样的:
exports.GetQuestions = function(query,requestify) { var request = require("request"); var options = { method: 'GET', url: 'https://api.stackexchange.com/2.2/search/advanced', qs: { order: 'desc', sort: 'activity', site: 'stackoverflow', q: 'Error: Can\'t find Python executable "C:\\Users\\harig\\AppData\\Local\\Programs\\Python\\Python36\\python.EXE", you can set the PYTHON env variable' }, headers: { 'postman-token': 'b0b78842-94cd-a0b9-39cc-0e099136900c', 'cache-control': 'no-cache', 'Accept': 'application/json' } }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); }); }
接口返回的响应头信息:
cache-control: private content-type: application/json; charset=utf-8 content-encoding: gzip access-control-allow-origin: * access-control-allow-methods: GET, POST access-control-allow-credentials: false x-content-type-options: nosniff date: Sun, 21 Jan 2018 16:12:19 GMT connection: close content-length: 4780
返回的乱码样本就像这样:
���������U����"�z�f%��-??ӵm��N�|�f&��fે�n�.""��DX�Ƀ�P��J�(�p�U�Q�N47 �1�M�.�|]�t5agA��0�rc �g�3��} +�Y�q/�pL��M�RƜGwt�B��ڍ�@���9(>s��ʀ6�@�w���e/��Mu�ʮ��9, �ML| �s9�a���ߑW�r�[����ߗa�������a�~6��>ͦ����u�3���a�|P-�ᣖ�S' � 侤�#v�D�PXM�i��ȹ��O�{2N�s��? ����ڝ���O_������/ ���ř��M3��w�ܾ����g"�� ���$�("%�r#S�Px3��;?4^}��n�S�f7U[���g7� a�cȩbҷ�Oq����X,8w�5Szp�P�y���rg� <�������m�;�u���|��aXJ��!��~X�bK�#�b5���,)W+����)������+n[cl()�����lC> okoSHcY��c\�TW0ƊLM ��ݒ���oN9دhV���t� �rj�� *�cPޝ�~l���E�́Ѳ�o3Dp�Eus侫��L��R�n��i�`+����DF���h $~377s=��W��xP��#�CAN�1�T�Ub0c$�e����S���&���B�}�~��Q�������m��m�������a�|���sL�Y;z8��T}�j~�]}���El�����]|��B�����*nt�^�,����� k' 7�J�IO�i�d�m�4"�N���DZ��1䞦'�[�&�j���~�6�).G��v=��gn��x4�6nh�����V��o�)���^ಧ�2����['6����z� �#�/���J���j+vD�xƍ)N����qC[C���U��Z|�����vh ���_��>�gd�9��v���.��i�U�zJ��,�*J��RBt�s��iӮo��f�^A3��$�"7�N��!�l�b,"��96�@�������C���.��a�52'a�v�U��9��v]�l�~kΎ��ԌG�藊<9�eN;]t��n�k?;cu� L�u}�t���q;৯��=�����Y��ZK������AL.�L
问题原因
仔细看响应头里的content-encoding: gzip,这说明Stack Exchange API返回的内容是经过gzip压缩的。Postman会自动识别并解压这类压缩内容,所以能正常显示JSON;但Node.js的request库默认不会自动处理gzip解压,所以拿到的是原始的压缩二进制数据,打印出来就是乱码。
解决方案
有两种简单的方法可以解决这个问题:
方法1:让request自动处理gzip
只需要在请求的options里添加gzip: true配置项,request就会自动识别并解压gzip内容:
exports.GetQuestions = function(query,requestify) { var request = require("request"); var options = { method: 'GET', url: 'https://api.stackexchange.com/2.2/search/advanced', qs: { order: 'desc', sort: 'activity', site: 'stackoverflow', q: 'Error: Can\'t find Python executable "C:\\Users\\harig\\AppData\\Local\\Programs\\Python\\Python36\\python.EXE", you can set the PYTHON env variable' }, headers: { 'postman-token': 'b0b78842-94cd-a0b9-39cc-0e099136900c', 'cache-control': 'no-cache', 'Accept': 'application/json' }, gzip: true // 新增这一行 }; request(options, function (error, response, body) { if (error) throw new Error(error); console.log(body); // 现在就能拿到正常的JSON了 }); }
方法2:手动用zlib解压
如果不想修改request的配置,也可以用Node.js内置的zlib模块手动解压返回的body:
exports.GetQuestions = function(query,requestify) { var request = require("request"); var zlib = require('zlib'); // 引入zlib模块 var options = { method: 'GET', url: 'https://api.stackexchange.com/2.2/search/advanced', qs: { order: 'desc', sort: 'activity', site: 'stackoverflow', q: 'Error: Can\'t find Python executable "C:\\Users\\harig\\AppData\\Local\\Programs\\Python\\Python36\\python.EXE", you can set the PYTHON env variable' }, headers: { 'postman-token': 'b0b78842-94cd-a0b9-39cc-0e099136900c', 'cache-control': 'no-cache', 'Accept': 'application/json' }, encoding: null // 设置为null,让body返回二进制数据 }; request(options, function (error, response, body) { if (error) throw new Error(error); // 判断是否是gzip压缩 if (response.headers['content-encoding'] === 'gzip') { zlib.gunzip(body, function(err, decoded) { if (err) throw err; console.log(decoded.toString()); // 解压后转成字符串就是正常的JSON }); } else { console.log(body.toString()); } }); }
验证效果
修改完代码后重新运行,就能正常拿到格式化的JSON响应了,再也不会看到乱码啦!
内容的提问来源于stack exchange,提问作者Hari Govind
相关产品推荐
相关产品推荐

