nodejs - pierwszy argument musi być łańcuchem znaków lub buforem - w przypadku używania response.write z http.request

93

Po prostu próbuję utworzyć serwer węzłowy, który wyprowadza stan HTTP podanego adresu URL.

Kiedy próbuję opróżnić odpowiedź z res.write, pojawia się błąd: rzuca nowy TypeError („pierwszy argument musi być ciągiem lub buforem”);

Ale jeśli zamienię je na console.log, wszystko jest w porządku (ale muszę je zapisać w przeglądarce, a nie w konsoli).

Kod to

var server = http.createServer(function (req, res) {
    res.writeHead(200, {"Content-Type": "text/plain"});

    request({
        uri: 'http://www.google.com',
        method: 'GET',
        maxRedirects:3
    }, function(error, response, body) {
        if (!error) {
            res.write(response.statusCode);
        } else {
            //response.end(error);
            res.write(error);
        }
    });     

    res.end();
});
server.listen(9999);

Uważam, że powinienem gdzieś dodać oddzwonienie, ale jestem dość zdezorientowany i każda pomoc jest mile widziana.

umutm
źródło

Odpowiedzi:

32

Żądanie przyjmuje metodę wywołania zwrotnego, jest asynchroniczna! Zakładam więc, że do czasu wykonania wywołania zwrotnego res.end()może zostać wywołany. Spróbuj zamknąć żądanie w wywołaniu zwrotnym.

Gaurav Agarwal
źródło
1
Zrobiłem to, a także dodałem .toString. Dzięki wielkie.
umutm
Wygląda na to, że zapomniałem. Właśnie to zrobiłem. Dzięki.
umutm,
1
@umutm Jest więcej dobrze napisanych i rozbudowanych odpowiedzi, prawdopodobnie powinieneś zaakceptować jedną z nich; dzięki czemu będzie widoczne dla każdego, kto zadaje to pytanie.
Gaurav Agarwal,
52

response.statusCodejest liczbą, np . response.statusCode === 200nie '200'. Jak mówi komunikat o błędzie, writeoczekuje obiektu stringlub Buffer, więc musisz go przekonwertować.

res.write(response.statusCode.toString());

Masz również rację co do komentarza oddzwonienia. res.end();powinien znajdować się wewnątrz wywołania zwrotnego, tuż pod Twoimi writewywołaniami.

loganfsmyth
źródło
Tak, to załatwiło sprawę. Jako nowicjusz nodejs nie wiedziałem o tym i bardzo dziękuję.
umutm
48

Otrzymuję ten komunikat o błędzie i wspomina o options.body

Miałem to pierwotnie

request.post({
    url: apiServerBaseUrl + '/v1/verify',
    body: {
        email: req.user.email
    }
});

Zmieniłem to na to:

request.post({
    url: apiServerBaseUrl + '/v1/verify',
    body: JSON.stringify({
        email: req.user.email
    })
});

i wydaje się, że teraz działa bez komunikatu o błędzie ... chociaż wygląda na błąd.

Myślę, że jest to bardziej oficjalny sposób:

 request.post({
        url: apiServerBaseUrl + '/v1/verify',
        json: true,
        body: {
            email: req.user.email
        }
    });
Alexander Mills
źródło
4
Twój problem jest inny, domyślnie oczekuje się, że body będzie łańcuchem lub buforem. Możesz również zmienić to (aby było możliwe do serializacji json), dodając json: true do opcji. Np .: request.post ({url: apiServerBaseUrl + '/ v1 / verify', body: {email: req.user.email}, json: true})
Nuno Tomas
2
Możesz użyć tego, aby uniknąć stringify javascript request.post({ url: apiServerBaseUrl + '/v1/verify', json: { email: req.user.email } }
bsorrentino
13

Cóż, oczywiście próbujesz wysłać coś, co nie jest łańcuchem ani buforem. :) Działa z konsolą, ponieważ konsola akceptuje wszystko. Prosty przykład:

var obj = { test : "test" };
console.log( obj ); // works
res.write( obj ); // fails

Jednym ze sposobów konwersji czegokolwiek na ciąg jest zrobienie tego:

res.write( "" + obj );

gdy próbujesz coś wysłać. Innym sposobem jest wywołanie .toString()metody:

res.write( obj.toString( ) );

Pamiętaj, że nadal może to nie być to, czego szukasz. Zawsze powinieneś przekazywać łańcuchy / bufory .writebez takich sztuczek.

Na marginesie: zakładam, że requestjest to operacja asynchroniczna. W takim przypadku res.end();zostanie wywołany przed jakimkolwiek zapisem, tj. Zapis i tak się nie powiedzie (ponieważ połączenie zostanie w tym momencie zamknięte). Przenieś tę linię do handlera:

request({
    uri: 'http://www.google.com',
    method: 'GET',
    maxRedirects:3
}, function(error, response, body) {
    if (!error) {
        res.write(response.statusCode);
    } else {
        //response.end(error);
        res.write(error);
    }
    res.end( );
});
kapryśny
źródło
Bardzo dziękuję za odpowiedź i szczegółowe informacje. I tak, przeniosłem res.end do programu obsługi. Zaakceptowałem @loganfsmyth tak, jak było wcześniej. Dzięki jeszcze raz.
umutm
1

jeśli chcesz zapisać obiekt JSON w odpowiedzi, zmień typ zawartości nagłówka na application / json

response.writeHead(200, {"Content-Type": "application/json"});
var d = new Date(parseURL.query.iso);
var postData = {
    "hour" : d.getHours(),
    "minute" : d.getMinutes(),
    "second" : d.getSeconds()
}
response.write(postData)
response.end();
Mohsin Muzawar
źródło
1

I jest jeszcze jedna możliwość (nie w tym przypadku) podczas pracy z ajaxem (XMLhttpRequest), podczas wysyłania informacji z powrotem do klienta należy użyć res.send (responsetext) zamiast res.end (responsetext)

Prajith P
źródło
1

Chociaż pytanie jest rozwiązane, dzielenie się wiedzą w celu wyjaśnienia prawidłowego znaczenia błędu.

Błąd mówi, że parametr potrzebny do danej funkcji przerywającej nie jest w wymaganym formacie, tj. Łańcuch lub bufor

Rozwiązaniem jest zmiana parametru na łańcuch

breakingFunction(JSON.stringify(offendingParameter), ... other params...);

lub bufor

breakingFunction(BSON.serialize(offendingParameter), ... other params...);
Zameer Ansari
źródło
0

Pierwszy argument musi być typu string lub Buffer. Otrzymano obiekt typu

 at write_

Otrzymałem podobny błąd podczas przekazywania danych do modułu żądania.

Przekazałem kolejny parametr, którym jest JSON: true i działa.

var option={
url:"https://myfirstwebsite/v1/appdata",
json:true,
body:{name:'xyz',age:30},
headers://my credential
}
rp(option)
.then((res)=>{
res.send({response:res});})
.catch((error)=>{
res.send({response:error});})
A. PRABIN SARAB
źródło