【问题标题】:Response encoding with node.js "request" module使用 node.js“请求”模块的响应编码
【发布时间】:2013-02-08 04:13:39
【问题描述】:

我正在尝试从 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,所以这似乎不需要)。

有人知道发生了什么吗?

FWIW,我在 OSX 10.8 上,节点是通过 macports 安装的 v0.8.20,请求是通过 npm 安装的 v2.14.0。

【问题讨论】:

    标签: node.js http character-encoding request bing


    【解决方案1】:

    您必须传递选项 {json:true} 才能启用响应的 json 解析

    【讨论】:

    • 问题在于编码,而不是格式,如果您阅读了我也尝试使用 ATOM 的问题。但问题是 18 个月前的问题,所以希望他们解决了。
    【解决方案2】:

    我认为您的请求身份验证不正确。必须在 request.get 之前提供身份验证。 请参阅request HTTP authentication 的文档。 qs 是一个必须传递给 request options 的对象,就像 url 和 auth 一样。 您也使用相同的req 进行第二次请求。您应该知道 request.get 为给定的 url 返回一个流。您使用req 的下一个请求将出错。

    如果您只需要 HTTPBasicAuth,这也应该可以工作

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

    回调参数有 3 个参数。第一个是适用时的错误(通常来自 http.Client 选项而不是 http.ClientRequest 对象)。第二个是 http.ClientResponse 对象。第三个是响应体 String 或 Buffer。 第二个对象是响应流。要使用它,您必须使用事件“数据”、“结束”、“错误”和“关闭”。

    请务必正确使用参数。

    【讨论】:

    • 不,流利的语法可以正确设置选项,只是文档记录很差。我的问题不是身份验证,我可以看到它有效并且我得到了经过身份验证的响应。我的问题是响应体损坏。
    【解决方案3】:

    我不确定请求库,但默认的 nodejs 对我来说效果很好。它似乎也比您的库更容易阅读,并且确实以块的形式返回。

    http://nodejs.org/api/http.html#http_http_request_options_callback 或 https (就像你的要求)http://nodejs.org/api/https.html#https_https_request_options_callback (虽然真的一样)

    关于选项的小提示:使用 url parse

    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 需要是您要发送的数据

    【讨论】:

    • TBH 我也尝试过这样做(虽然使用https.get 而不是.request),但我无法让它工作,我一定是做错了。无论如何,它现在似乎可以工作,所以如果有人没有提供使用 request 模块的修复程序,我无论如何都会接受你的回答。谢谢!
    • 这可能与 JSON 实际上格式错误有关。如果您有一个包含多字节字符的字符串,并且您将Content-Length 作为params.length 传递,那么您是说内容的字节长度与字符串中的字符数相同。这不适用于多字节字符。而不是{"name": "feeé"},你的api可能会得到{"name": "feeé"
    猜你喜欢
    • 2018-01-05
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 2019-07-20
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多