使用Node.js中的“request”模块进行响应编码

7

我正在尝试从Bing搜索API中获取数据,由于现有的库似乎是基于已停用的旧API开发的,所以我想试着自己使用request库,这似乎是最常用的库之一。 我的代码如下:

var SKEY           =  "myKey...." , 
    ServiceRootURL =  'https://api.datamarket.azure.com/Bing/Search/v1/Composite';

function getBingData(query, top, skip, cb) {
    var params = {
         Sources: "'web'", 
         Query: "'"+query+"'", 
         '$format': "JSON", 
         '$top': top, '$skip': skip
       },
       req = request.get(ServiceRootURL).auth(SKEY, SKEY, false).qs(params);
    request(req, cb)
}

getBingData("bookline.hu", 50, 0, someCallbackWhichParsesTheBody)

Bing返回一些JSON数据,有时我可以处理它,但是如果响应体包含大量的非ASCII字符,则JSON.parse会抱怨字符串格式不正确。我尝试切换到ATOM内容类型,但没有任何区别,xml无效。在request()回调中提供的响应主体实际上显示了错误代码。因此,我尝试使用一些Python代码进行相同的请求,似乎总是正常工作。供参考:
r = requests.get(
       'https://api.datamarket.azure.com/Bing/Search/v1/Composite?Sources=%27web%27&Query=%27sexy%20cosplay%20girls%27&$format=json', 
        auth=HTTPBasicAuth(SKEY,SKEY))
stuffWithResponse(r.json())

我无法重现使用较小响应(例如限制结果数量)时出现的问题,并且无法确定导致该问题的单个结果(通过逐步增加偏移量)。我的印象是响应以某种方式被分块读取、转码并以错误的方式重新组合,这意味着如果某个多字节字符被拆分,则json/atom数据会变得无效,在较大的响应中发生,但不发生在小的响应中。

作为新手,我不确定是否有什么我应该做的事情(在某个地方设置编码?Bing返回UTF-8,因此似乎不需要这样做)。

任何人都有任何想法吗?

顺便说一下,我正在使用OSX 10.8,node是通过macports安装的v0.8.20,请求是通过npm安装的v2.14.0。

3个回答

1
我不确定请求库,但默认的nodejs库对我来说很好用。它似乎比你的库更容易阅读,并且确实会分块返回。 http://nodejs.org/api/http.html#http_http_request_options_callback 或者对于https(像你的req一样)http://nodejs.org/api/https.html#https_https_request_options_callback(其实是一样的)
关于选项的小提示:使用url解析。
var url = require('url');

var params = '{}'

var dataURL = url.parse(ServiceRootURL);
var post_options = {  
    hostname: dataURL.hostname,
    port: dataURL.port || 80,
    path: dataURL.path,
    method: 'GET',  
    headers: {  
        'Content-Type': 'application/json; charset=utf-8',  
        'Content-Length': params.length  
    }  
};

显然,params需要是您要发送的数据。

说实话,我也尝试过这种方式(不过使用的是https.get而不是.request),但是我无法让它正常工作,我一定做错了什么。不管怎样,现在看起来它能正常工作了,所以如果没有人提供使用request模块的修复方法,我还是会接受你的答案。谢谢! - riffraff
1
可能更多地与JSON实际上是格式不正确有关。如果您有一个包含多字节字符的字符串,并将Content-Length作为params.length传递,则表示内容的字节长度与字符串中字符数相同。这在多字节字符中是不正确的。您的API可能会收到{"name": "feeé"而不是{"name": "feeé"} - amsross

0
你需要传递选项{json:true}来启用响应的JSON解析。

问题在于编码,而不是格式。如果您阅读了问题,我也尝试过使用ATOM。但这个问题已经有18个月了,希望他们已经解决了它。 - riffraff

0

我认为你的请求身份验证不正确。在请求获取之前,必须提供身份验证。 请参阅request HTTP authentication文档。qs是一个对象,必须像url和auth一样传递给request options。 另外,你正在对第二个请求使用同一个req。你应该知道request.get返回给定url的GET流。你接下来使用req的请求会出错。

如果你只需要HTTP基本身份验证,这也应该可以工作。

//remove req = request.get and subsequent request
request.get('http://some.server.com/', {
  'auth': {
    'user': 'username',
    'pass': 'password',
    'sendImmediately': false
  }
 },function (error, response, body) {
});

回调参数有三个参数。第一个是错误(通常来自http.Client选项而不是http.ClientRequest对象)。第二个是http.ClientResponse对象。第三个是响应体字符串或缓冲区。
第二个对象是响应流。要使用它,必须使用事件“data”,“end”,“error”和“close”。
请确保正确使用参数。

不,流畅的语法会正确设置选项,只是文档记录得相当差。我的问题不在于身份验证,我可以看到它起作用并获得认证响应。我的问题在于混淆的响应正文。 - riffraff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接