Synchrone Anforderung in Node.js.


98

Wenn ich 3 http API in sequentieller Reihenfolge aufrufen muss, was wäre eine bessere Alternative zum folgenden Code:

http.get({ host: 'www.example.com', path: '/api_1.php' }, function(res) { 
  res.on('data', function(d) { 

    http.get({ host: 'www.example.com', path: '/api_2.php' }, function(res) { 
      res.on('data', function(d) { 

        http.get({ host: 'www.example.com', path: '/api_3.php' }, function(res) { 
          res.on('data', function(d) { 


          });
        });
        }
      });
    });
    }
  });
});
}

Abgesehen davon, dass Sie das aufräumen, glaube ich nicht, dass Sie es besser machen können.
hvgotcodes

2
Warum müssen sie in Ordnung sein?
Raynos

11
@ Raynos Möglicherweise benötigen Sie einige Daten von api_1, bevor Sie wissen, was Sie an api_2 senden sollen
andyortlieb

9
Es ist erwähnenswert, dass Futures ziemlich veraltet ist.
Benjamin Gruenbaum

1
Titel und Frage widersprechen sich. Sie beschreiben in Ihrer Frage keine synchrone Anforderung, sondern eine Folge von Anforderungen, die normalerweise jeweils asynchron auftreten. Großer Unterschied - ein synchroner Aufruf blockiert und eine Folge von asynchronen Aktionen blockiert nicht (blockieren Sie die Benutzeroberfläche, blockieren Sie den Server für die Verarbeitung anderer Anforderungen). Im Folgenden finden Sie eine Antwort, in der die sync-requestBibliothek erwähnt wird. Dies ist eine gute Antwort auf den Titel dieser Frage, aber keine Antwort darauf, was der Code der Frage impliziert. Die Antwort unten über Versprechen ist eine bessere Antwort darauf. Was hast du gemeint?
Jake

Antworten:


69

Verwenden Sie aufgeschobene wie Futures.

var sequence = Futures.sequence();

sequence
  .then(function(next) {
     http.get({}, next);
  })
  .then(function(next, res) {
     res.on("data", next);
  })
  .then(function(next, d) {
     http.get({}, next);
  })
  .then(function(next, res) {
    ...
  })

Wenn Sie den Bereich weitergeben müssen, tun Sie einfach so etwas

  .then(function(next, d) {
    http.get({}, function(res) {
      next(res, d);
    });
  })
  .then(function(next, res, d) { })
    ...
  })

Bitte versuchen Sie es mit IcedCoffeScript, mit dem Sie auf nodejs warten und aufschieben können.
Thanigainathan

Ist das nicht blockierend? Ich meine, es blockiert für die nächste Funktion in der Zeile, aber dies blockiert nicht die Ausführung anderer asynchroner Funktionen, oder?
Oktav

1
Ja, zurückgestellte Methoden sind nicht blockierend / asynchron.
dvlsg

4
Die ES6 Promise API sollte dies effektiv ersetzen, selbst laut dem Autor von "Futures"
Alexander Mills

Futures sind sehr alt und veraltet. Siehe stattdessen q.
Jim Aho

53

Ich mag auch die Lösung von Raynos, aber ich bevorzuge eine andere Flusskontrollbibliothek.

https://github.com/caolan/async

Je nachdem, ob Sie die Ergebnisse für jede nachfolgende Funktion benötigen, würde ich entweder Serien, Parallel oder Wasserfall verwenden.

Serien, wenn sie seriell ausgeführt werden müssen, Sie aber nicht unbedingt die Ergebnisse in jedem nachfolgenden Funktionsaufruf benötigen.

Parallel, wenn sie parallel ausgeführt werden können, benötigen Sie nicht die Ergebnisse von jeder während jeder parallelen Funktion, und Sie benötigen einen Rückruf, wenn alle abgeschlossen sind.

Wasserfall, wenn Sie die Ergebnisse in jeder Funktion ändern und zur nächsten übergehen möchten

endpoints = 
 [{ host: 'www.example.com', path: '/api_1.php' },
  { host: 'www.example.com', path: '/api_2.php' },
  { host: 'www.example.com', path: '/api_3.php' }];

async.mapSeries(endpoints, http.get, function(results){
    // Array of results
});

9
var http = require ('http');
Elle Mundy

7
Hah. example.com ist eigentlich eine Domain, die für solche Dinge entwickelt wurde. Beeindruckend.
Meawoppl

Der async.series-Code funktioniert zumindest ab async v0.2.10 nicht. series () akzeptiert nur bis zu zwei Argumente und führt die Elemente des ersten Arguments als Funktionen aus. Daher gibt async einen Fehler aus, der versucht, die Objekte als Funktionen auszuführen.
Deckel

1
Mit forEachAsync ( github.com/FuturesJS/forEachAsync ) können Sie ähnliche Aktionen wie mit diesem Code ausführen .
Deckel

Das macht genau das, was ich wollte. Danke dir!
aProperFox

33

Sie können dies mit meiner Common Node-Bibliothek tun :

function get(url) {
  return new (require('httpclient').HttpClient)({
    method: 'GET',
      url: url
    }).finish().body.read().decodeToString();
}

var a = get('www.example.com/api_1.php'), 
    b = get('www.example.com/api_2.php'),
    c = get('www.example.com/api_3.php');

3
Mist, ich stimmte zu denken, es würde funktionieren und es funktioniert nicht :(require(...).HttpClient is not a constructor
moeiscool

29

Sync-Anfrage

Die mit Abstand einfachste, die ich gefunden und verwendet habe, ist die Synchronisierungsanforderung , die sowohl den Knoten als auch den Browser unterstützt!

var request = require('sync-request');
var res = request('GET', 'http://google.com');
console.log(res.body.toString('utf-8'));

Das war's, keine verrückte Konfiguration, keine komplexe lib-Installation, obwohl es einen lib-Fallback gibt. Funktioniert einfach. Ich habe hier andere Beispiele ausprobiert und war ratlos, als es viel mehr Setup gab oder Installationen nicht funktionierten!

Anmerkungen:

Das Beispiel, das die Synchronisierungsanforderung verwendet, spielt sich bei der Verwendung nicht gut ab res.getBody(). Get body akzeptiert lediglich eine Codierung und konvertiert die Antwortdaten. Mach es einfach res.body.toString(encoding)stattdessen.


Ich habe festgestellt, dass die Synchronisierungsanforderung sehr langsam ist. Am Ende habe ich eine andere verwendet, github.com/dhruvbird/http-sync, die in meinem Fall zehnmal schneller ist.
Filip Spiridonov

Ich hatte keine langsamen Läufe dafür. Dies erzeugt einen untergeordneten Prozess. Wie viele CPUs verwendet Ihr System und welche Version des Knotens verwenden Sie? Ich würde gerne wissen, ob ich wechseln muss oder nicht.
jemiloii

Ich stimme Filip zu, das ist langsam.
Rambo7

Das Gleiche habe ich um Flip gebeten, aber keine Antwort erhalten: Wie viele CPUs verwendet Ihr System und welche Version des Knotens verwenden Sie?
jemiloii

Dies verbraucht eine erhebliche Menge an CPU, die für die Verwendung in der Produktion nicht empfohlen wird.
Moeiscool

20

Ich würde eine rekursive Funktion mit einer Liste von Apis verwenden

var APIs = [ '/api_1.php', '/api_2.php', '/api_3.php' ];
var host = 'www.example.com';

function callAPIs ( host, APIs ) {
  var API = APIs.shift();
  http.get({ host: host, path: API }, function(res) { 
    var body = '';
    res.on('data', function (d) {
      body += d; 
    });
    res.on('end', function () {
      if( APIs.length ) {
        callAPIs ( host, APIs );
      }
    });
  });
}

callAPIs( host, APIs );

bearbeiten: Version anfordern

var request = require('request');
var APIs = [ '/api_1.php', '/api_2.php', '/api_3.php' ];
var host = 'www.example.com';
var APIs = APIs.map(function (api) {
  return 'http://' + host + api;
});

function callAPIs ( host, APIs ) {
  var API = APIs.shift();
  request(API, function(err, res, body) { 
    if( APIs.length ) {
      callAPIs ( host, APIs );
    }
  });
}

callAPIs( host, APIs );

edit: request / async version

var request = require('request');
var async = require('async');
var APIs = [ '/api_1.php', '/api_2.php', '/api_3.php' ];
var host = 'www.example.com';
var APIs = APIs.map(function (api) {
  return 'http://' + host + api;
});

async.eachSeries(function (API, cb) {
  request(API, function (err, res, body) {
    cb(err);
  });
}, function (err) {
  //called when all done, or error occurs
});

Dies ist die Methode, die ich angewendet habe, da ich eine variable Liste von Anfragen habe (600 Elemente und wachsende). Es gibt jedoch ein Problem mit Ihrem Code: Das Datenereignis wird mehrmals pro Anforderung ausgegeben, wenn die API-Ausgabe größer als die Blockgröße ist. Sie möchten die Daten wie folgt "puffern": var body = ''; res.on ('data', function (data) {body + = data;}). on ('end', function () {callback (body); if (APIs.length) callAPIs (host, APIs);} );
Ankit Aggarwal

Aktualisiert. Ich wollte nur zeigen, wie das Problem durch Rekursion einfacher / flexibler gemacht werden kann. Persönlich verwende ich immer das Anforderungsmodul für solche Dinge, da Sie damit problemlos mehrere Rückrufe überspringen können.
Generalhenry

@generalhenry, wie würde ich das machen, wenn ich das Anforderungsmodul verwenden wollte? Können Sie ein Code-Snippet anbieten, das die oben genannten Anforderungen erfüllt?
Scotty

Ich habe eine Anforderungsversion und eine Anforderungs- / Async-Version hinzugefügt.
Generalhenry

5

Es scheint, dass Lösungen für dieses Problem niemals enden, hier noch eine :)

// do it once.
sync(fs, 'readFile')

// now use it anywhere in both sync or async ways.
var data = fs.readFile(__filename, 'utf8')

http://alexeypetrushin.github.com/synchronize


Obwohl die von Ihnen verknüpfte Bibliothek DOES eine Lösung für das OP-Problem bietet, ist fs.readFile in Ihrem Beispiel immer synchron.
Eric

1
Nein, Sie können einen Rückruf explizit bereitstellen und ihn auf Wunsch als asynchrone Version verwenden.
Alex Craft

1
Das Beispiel war jedoch für http-Anforderungen, nicht für die Dateisystemkommunikation.
Seth

5

Eine andere Möglichkeit besteht darin, einen Rückruf einzurichten, der erledigte Aufgaben verfolgt:

function onApiResults(requestId, response, results) {
    requestsCompleted |= requestId;

    switch(requestId) {
        case REQUEST_API1:
            ...
            [Call API2]
            break;
        case REQUEST_API2:
            ...
            [Call API3]
            break;
        case REQUEST_API3:
            ...
            break;
    }

    if(requestId == requestsNeeded)
        response.end();
}

Weisen Sie dann einfach jedem eine ID zu, und Sie können Ihre Anforderungen festlegen, für die Aufgaben ausgeführt werden müssen, bevor die Verbindung geschlossen wird.

const var REQUEST_API1 = 0x01;
const var REQUEST_API2 = 0x02;
const var REQUEST_API3 = 0x03;
const var requestsNeeded = REQUEST_API1 | REQUEST_API2 | REQUEST_API3;

Okay, es ist nicht schön. Es ist nur eine andere Möglichkeit, sequentielle Anrufe zu tätigen. Es ist bedauerlich, dass NodeJS nicht die grundlegendsten synchronen Anrufe bereitstellt. Aber ich verstehe, was der Reiz zur Asynchronität ist.


4

benutze sequenty.

sudo npm install sequenty

oder

https://github.com/AndyShin/sequenty

sehr einfach.

var sequenty = require('sequenty'); 

function f1(cb) // cb: callback by sequenty
{
  console.log("I'm f1");
  cb(); // please call this after finshed
}

function f2(cb)
{
  console.log("I'm f2");
  cb();
}

sequenty.run([f1, f2]);

Sie können auch eine Schleife wie diese verwenden:

var f = [];
var queries = [ "select .. blah blah", "update blah blah", ...];

for (var i = 0; i < queries.length; i++)
{
  f[i] = function(cb, funcIndex) // sequenty gives you cb and funcIndex
  {
    db.query(queries[funcIndex], function(err, info)
    {
       cb(); // must be called
    });
  }
}

sequenty.run(f); // fire!

3

Die Verwendung der Anforderungsbibliothek kann dazu beitragen, die Cruft zu minimieren:

var request = require('request')

request({ uri: 'http://api.com/1' }, function(err, response, body){
    // use body
    request({ uri: 'http://api.com/2' }, function(err, response, body){
        // use body
        request({ uri: 'http://api.com/3' }, function(err, response, body){
            // use body
        })
    })
})

Für maximale Attraktivität sollten Sie jedoch eine Kontrollflussbibliothek wie Step ausprobieren. Sie können damit auch Anforderungen parallelisieren, sofern dies akzeptabel ist:

var request = require('request')
var Step    = require('step')

// request returns body as 3rd argument
// we have to move it so it works with Step :(
request.getBody = function(o, cb){
    request(o, function(err, resp, body){
        cb(err, body)
    })
}

Step(
    function getData(){
        request.getBody({ uri: 'http://api.com/?method=1' }, this.parallel())
        request.getBody({ uri: 'http://api.com/?method=2' }, this.parallel())
        request.getBody({ uri: 'http://api.com/?method=3' }, this.parallel())
    },
    function doStuff(err, r1, r2, r3){
        console.log(r1,r2,r3)
    }
)

3

Ab 2018 können wir mit ES6-Modulen und Promises eine solche Funktion schreiben:

import { get } from 'http';

export const fetch = (url) => new Promise((resolve, reject) => {
  get(url, (res) => {
    let data = '';
    res.on('end', () => resolve(data));
    res.on('data', (buf) => data += buf.toString());
  })
    .on('error', e => reject(e));
});

und dann in einem anderen Modul

let data;
data = await fetch('http://www.example.com/api_1.php');
// do something with data...
data = await fetch('http://www.example.com/api_2.php');
// do something with data
data = await fetch('http://www.example.com/api_3.php');
// do something with data

Der Code muss in einem asynchronen Kontext ausgeführt werden (mit asyncSchlüsselwort)


2

Es gibt viele Kontrollflussbibliotheken - ich mag conseq (... weil ich es geschrieben habe). on('data')Kann auch mehrmals ausgelöst werden , verwenden Sie also eine REST-Wrapper-Bibliothek wie restler .

Seq()
  .seq(function () {
    rest.get('http://www.example.com/api_1.php').on('complete', this.next);
  })
  .seq(function (d1) {
    this.d1 = d1;
    rest.get('http://www.example.com/api_2.php').on('complete', this.next);
  })
  .seq(function (d2) {
    this.d2 = d2;
    rest.get('http://www.example.com/api_3.php').on('complete', this.next);
  })
  .seq(function (d3) {
    // use this.d1, this.d2, d3
  })

2

Dies wurde von Raynos gut beantwortet. In der Sequenzbibliothek wurden jedoch Änderungen vorgenommen, seit die Antwort veröffentlicht wurde.

Folgen Sie diesem Link, um die Sequenz zum Laufen zu bringen: https://github.com/FuturesJS/sequence/tree/9daf0000289954b85c0925119821752fbfb3521e .

So können Sie es zum Laufen bringen npm install sequence:

var seq = require('sequence').Sequence;
var sequence = seq.create();

seq.then(function call 1).then(function call 2);

1

Hier ist meine Version von @ andy-shin nacheinander mit Argumenten im Array anstelle des Index:

function run(funcs, args) {
    var i = 0;
    var recursive = function() {
        funcs[i](function() {
            i++;
            if (i < funcs.length)
                recursive();
        }, args[i]);
    };
    recursive();
}

1

...4 Jahre später...

Hier ist eine originelle Lösung mit dem Framework Danf (Sie benötigen keinen Code für diese Art von Dingen, nur einige Konfigurationen):

// config/common/config/sequences.js

'use strict';

module.exports = {
    executeMySyncQueries: {
        operations: [
            {
                order: 0,
                service: 'danf:http.router',
                method: 'follow',
                arguments: [
                    'www.example.com/api_1.php',
                    'GET'
                ],
                scope: 'response1'
            },
            {
                order: 1,
                service: 'danf:http.router',
                method: 'follow',
                arguments: [
                    'www.example.com/api_2.php',
                    'GET'
                ],
                scope: 'response2'
            },
            {
                order: 2,
                service: 'danf:http.router',
                method: 'follow',
                arguments: [
                    'www.example.com/api_3.php',
                    'GET'
                ],
                scope: 'response3'
            }
        ]
    }
};

Verwenden Sie denselben orderWert für Operationen, die parallel ausgeführt werden sollen.

Wenn Sie noch kürzer sein möchten, können Sie einen Erfassungsprozess verwenden:

// config/common/config/sequences.js

'use strict';

module.exports = {
    executeMySyncQueries: {
        operations: [
            {
                service: 'danf:http.router',
                method: 'follow',
                // Process the operation on each item
                // of the following collection.
                collection: {
                    // Define the input collection.
                    input: [
                        'www.example.com/api_1.php',
                        'www.example.com/api_2.php',
                        'www.example.com/api_3.php'
                    ],
                    // Define the async method used.
                    // You can specify any collection method
                    // of the async lib.
                    // '--' is a shorcut for 'forEachOfSeries'
                    // which is an execution in series.
                    method: '--'
                },
                arguments: [
                    // Resolve reference '@@.@@' in the context
                    // of the input item.
                    '@@.@@',
                    'GET'
                ],
                // Set the responses in the property 'responses'
                // of the stream.
                scope: 'responses'
            }
        ]
    }
};

Weitere Informationen finden Sie in der Übersicht des Frameworks.


1

Ich bin hier gelandet, weil ich http.request einschränken musste (~ 10.000 Aggregationsabfragen zur elastischen Suche, um einen Analysebericht zu erstellen). Das Folgende hat gerade meine Maschine erstickt.

for (item in set) {
    http.request(... + item + ...);
}

Meine URLs sind sehr einfach, so dass dies möglicherweise nicht trivial auf die ursprüngliche Frage zutrifft, aber ich denke, es ist potenziell anwendbar und es lohnt sich, hier für Leser zu schreiben, die hier mit ähnlichen Problemen wie ich landen und eine triviale JavaScript-Lösung ohne Bibliothek wünschen.

Mein Job war nicht auftragsabhängig und mein erster Ansatz war, ihn in ein Shell-Skript zu packen, um ihn zu zerlegen (weil ich neu in JavaScript bin). Das war funktionell aber nicht zufriedenstellend. Meine JavaScript-Auflösung bestand am Ende darin, Folgendes zu tun:

var stack=[];
stack.push('BOTTOM');

function get_top() {
  var top = stack.pop();
  if (top != 'BOTTOM')
    collect(top);
}

function collect(item) {
    http.request( ... + item + ...
    result.on('end', function() {
      ...
      get_top();
    });
    );
}

for (item in set) {
   stack.push(item);
}

get_top();

Es sieht aus wie eine gegenseitige Rekursion zwischen collect und get_top . Ich bin nicht sicher , ist es in der Tat , da das System asynchron ist und die Funktion Collect schließt mit einem Rückruf für den Fall , verstaute bei auf. ( ‚Ende‘ .

Ich denke, es ist allgemein genug, um auf die ursprüngliche Frage anzuwenden. Wenn wie in meinem Szenario die Reihenfolge / Menge bekannt ist, können alle URLs / Schlüssel in einem Schritt auf den Stapel verschoben werden. Wenn sie im Laufe der Zeit berechnet werden, kann die Funktion on ('end' die nächste URL auf dem Stapel kurz vor get_top () verschieben . Wenn überhaupt, ist das Ergebnis weniger verschachtelt und kann möglicherweise einfacher umgestaltet werden, wenn die API aufgerufen wird Änderungen.

Mir ist klar, dass dies effektiv der einfachen rekursiven Version von @ generalhenry oben entspricht (also habe ich das positiv bewertet!)


0

Super Anfrage

Dies ist ein weiteres synchrones Modul, das auf Anfrage basiert und Versprechen verwendet. Super einfach zu bedienen, funktioniert gut mit Mokka-Tests.

npm install super-request

request("http://domain.com")
    .post("/login")
    .form({username: "username", password: "password"})
    .expect(200)
    .expect({loggedIn: true})
    .end() //this request is done 
    //now start a new one in the same session 
    .get("/some/protected/route")
    .expect(200, {hello: "world"})
    .end(function(err){
        if(err){
            throw err;
        }
    });

0

Dieser Code kann verwendet werden, um eine Reihe von Versprechungen synchron und nacheinander auszuführen, wonach Sie Ihren endgültigen Code im .then()Aufruf ausführen können .

const allTasks = [() => promise1, () => promise2, () => promise3];

function executePromisesSync(tasks) {
  return tasks.reduce((task, nextTask) => task.then(nextTask), Promise.resolve());
}

executePromisesSync(allTasks).then(
  result => console.log(result),
  error => console.error(error)
);

0

Ich habe genau das bekommen, was Sie (und ich) wollten, ohne Wartezeiten, Versprechen oder Einschlüsse einer (externen) Bibliothek (außer unserer eigenen).

So geht's:

Wir werden ein C ++ - Modul erstellen, das zu node.js passt, und diese C ++ - Modulfunktion wird die HTTP-Anforderung stellen und die Daten als Zeichenfolge zurückgeben. Sie können dies direkt verwenden, indem Sie Folgendes tun:

var myData = newModule.get(url);

SIND SIE BEREIT , loszulegen?

Schritt 1: Erstellen Sie einen neuen Ordner an einer anderen Stelle auf Ihrem Computer. Wir verwenden diesen Ordner nur zum Erstellen der Datei module.node (kompiliert aus C ++). Sie können sie später verschieben.

In dem neuen Ordner (ich habe meinen in mynewFolder / src für die Organisation abgelegt):

npm init

dann

npm install node-gyp -g

Jetzt mache 2 neue Dateien: 1, etwas.cpp genannt und füge diesen Code ein (oder ändere ihn, wenn du willst):

#pragma comment(lib, "urlmon.lib")
#include <sstream>
#include <WTypes.h>  
#include <node.h>
#include <urlmon.h> 
#include <iostream>
using namespace std;
using namespace v8;

Local<Value> S(const char* inp, Isolate* is) {
    return String::NewFromUtf8(
        is,
        inp,
        NewStringType::kNormal
    ).ToLocalChecked();
}

Local<Value> N(double inp, Isolate* is) {
    return Number::New(
        is,
        inp
    );
}

const char* stdStr(Local<Value> str, Isolate* is) {
    String::Utf8Value val(is, str);
    return *val;
}

double num(Local<Value> inp) {
    return inp.As<Number>()->Value();
}

Local<Value> str(Local<Value> inp) {
    return inp.As<String>();
}

Local<Value> get(const char* url, Isolate* is) {
    IStream* stream;
    HRESULT res = URLOpenBlockingStream(0, url, &stream, 0, 0);

    char buffer[100];
    unsigned long bytesReadSoFar;
    stringstream ss;
    stream->Read(buffer, 100, &bytesReadSoFar);
    while(bytesReadSoFar > 0U) {
        ss.write(buffer, (long long) bytesReadSoFar);
        stream->Read(buffer, 100, &bytesReadSoFar);
    }
    stream->Release();
    const string tmp = ss.str();
    const char* cstr = tmp.c_str();
    return S(cstr, is);
}

void Hello(const FunctionCallbackInfo<Value>& arguments) {
    cout << "Yo there!!" << endl;

    Isolate* is = arguments.GetIsolate();
    Local<Context> ctx = is->GetCurrentContext();

    const char* url = stdStr(arguments[0], is);
    Local<Value> pg = get(url,is);

    Local<Object> obj = Object::New(is);
    obj->Set(ctx,
        S("result",is),
        pg
    );
    arguments.GetReturnValue().Set(
       obj
    );

}

void Init(Local<Object> exports) {
    NODE_SET_METHOD(exports, "get", Hello);
}

NODE_MODULE(cobypp, Init);

Erstellen Sie nun eine neue Datei im selben Verzeichnis mit dem Namen something.gypund legen Sie (so etwas) darin ab:

{
   "targets": [
       {
           "target_name": "cobypp",
           "sources": [ "src/cobypp.cpp" ]
       }
   ]
}

Fügen Sie nun in der Datei package.json Folgendes hinzu: "gypfile": true,

Jetzt: in der Konsole, node-gyp rebuild

Wenn es den gesamten Befehl durchläuft und am Ende fehlerfrei "ok" sagt, können Sie (fast) loslegen. Wenn nicht, hinterlassen Sie einen Kommentar.

Wenn es funktioniert, gehen Sie zu build / Release / cobypp.node (oder wie auch immer es für Sie heißt), kopieren Sie es in Ihren Hauptordner node.js und dann in node.js:

var myCPP = require("./cobypp")
var myData = myCPP.get("http://google.com").result;
console.log(myData);

..

response.end(myData);//or whatever
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.