2013-02-22 25 views
7

Próbuję pobrać dane z interfejsu API wyszukiwania Bing, a ponieważ istniejące biblioteki wydają się być oparte na starych, wycofanych interfejsach API, chciałem sam spróbować użyć biblioteki request, która wydaje się być najczęstszą biblioteką do tego. Mój kod wyglądaKodowanie odpowiedzi za pomocą modułu "request" node.js

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 zwraca jakąś JSON i mogę z nim pracować, ale czasami jeśli ciało odpowiedź zawiera dużą ilość niezarejestrowanych znaków ASCII JSON.parse skarży się, że łańcuch jest uszkodzony. Próbowałem przejść do typu zawartości ATOM, ale nie było różnicy, xml był nieprawidłowy. Sprawdzanie treści odpowiedzi, jaka jest dostępna w wywołaniu zwrotnym request(), pokazuje zły kod.

Więc próbowałem tego samego żądania z pewnym kodem Pythona, który wydaje się działać dobrze cały czas. Dla porównania:

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()) 

nie jestem w stanie odtworzyć problemu z mniejszymi odpowiedzi (na przykład ograniczenie liczby wyników) oraz w stanie zidentyfikować pojedynczy wynik, który powoduje problem (poprzez intensyfikację offset). Mam wrażenie, że odpowiedź zostanie odczytana w kawałkach, w jakiś sposób transkodowana i złożona ponownie w zły sposób, co oznacza, że ​​dane json/atom stają się nieważne, jeśli jakiś znak wielobajtowy zostanie podzielony, co dzieje się w przypadku większych odpowiedzi, ale nie małych.

Będąc nowym węzłem, nie jestem pewien, czy jest coś, co powinienem robić (ustawienie kodowania gdzieś? Bing zwraca UTF-8, więc nie wydaje się to konieczne).

Ktoś ma pojęcie o tym, co się dzieje?

FWIW, jestem na OSX 10.8, węzeł jest v0.8.20 zainstalowany przez macports, żądanie jest v2.14.0 zainstalowane przez npm.

Odpowiedz

1

Nie jestem pewien co do biblioteki żądań, ale domyślny nodejs działa dobrze dla mnie. Wydaje się również dużo łatwiejsze do odczytania niż twoja biblioteka i rzeczywiście wraca w porcjach.

http://nodejs.org/api/http.html#http_http_request_options_callback lub https (jak twój req) http://nodejs.org/api/https.html#https_https_request_options_callback (ten sam naprawdę chociaż)

Dla opcji mała wskazówka: Stosowanie url analizowania

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 
    } 
}; 

oczywiście params musi być dane które chcę wysłać

+0

TBH Próbowałem zrobić to w ten sposób (choć z użyciem 'https.get' zamiast' .request') zbyt ale nie mogłem go uruchomić, musiałem coś zepsuć. W każdym razie wydaje się, że działa teraz, więc i tak przyjmuję twoją odpowiedź, jeśli ktoś nie zapewni poprawki do używania modułu 'request'. Dzięki! – riffraff

+1

Może to mieć więcej wspólnego z faktem, że JSON jest w rzeczywistości zniekształcony. Jeśli masz ciąg znaków zawierający znak wielobajtowy i przekazujesz 'Content-Length' jako' params.length', wtedy mówisz, że zawartość ma taką samą długość bajtu co liczba znaków w ciągu znaków. Nie dotyczy to znaków wielobajtowych. Zamiast '{" name ":" feeé "}', twój api prawdopodobnie otrzymuje '{" name ":" feeé "' – amsross

0

Myślę, że twoje uwierzytelnienie żądania jest nieprawidłowe. Uwierzytelnienie należy podać przed request.get. Zobacz dokumentację dla request HTTP authentication. qs to obiekt, który musi zostać przekazany do request options, podobnie jak adresy URL i uwierzytelnienia. Również używasz tego samego req dla drugiego żądania. Powinieneś wiedzieć, że request.get zwraca strumień dla GET podanego adresu url. Twoja kolejna prośba za pomocą req pójdzie źle.

Jeśli potrzebujesz tylko HTTPBasicAuth, to powinno również pracować

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

Wywołanie zwrotne argumentem pobiera 3 argumenty. Pierwszym z nich jest błąd, jeśli dotyczy (zwykle z opcji http.Client, a nie z obiektu http.ClientRequest). Drugi to obiekt http.ClientResponse. Trzeci to ciało odpowiedzi String lub Buffer. Drugi obiekt to strumień odpowiedzi. Aby z niego skorzystać, musisz użyć zdarzeń "data", "koniec", "błąd" i "zamknij".

Należy użyć argumentów poprawnie.

+0

nie, płynna składnia poprawnie ustawia opcje, jest po prostu słabo udokumentowana. Mój problem nie polega na uwierzytelnianiu, widzę, że działa i otrzymuję uwierzytelnioną odpowiedź. Moim problemem jest zniekształcone ciało odpowiedzi. – riffraff

0

Trzeba zdać opcję {json: true}, aby umożliwić json parsowania odpowiedzi

+0

problemem jest kodowanie, a nie formatowanie, jeśli przeczytałeś pytanie, które próbowałem również z ATOM. Ale pytanie ma 18 miesięcy, więc mam nadzieję, że to naprawili. – riffraff