вторник, 4 июля 2017 г.

Node.js Шпаргалка по API HTTP Server и Client

const http = require('http');
const net = require('net');
const url = require('url');

// ============== COMMON ==============

console.log(http.METHODS);
console.log(http.STATUS_CODES);
console.log(http.globalAgent);

// ============== Server ==============

const server = http.createServer();

server.maxHeadersCount = 2000;

server.keepAliveTimeout = 5000;

server.timeout = 120000;
server.setTimeout(120000, function () {
    console.log('Server timeout');
});

server.on('connection', function (socket) {
    console.log('Client connected');
});

// Используется только, если запрос с типом GET или POST
server.on('request', function (request, response) {
    console.log(request.headers);
    console.log(request.rawHeaders);
    console.log(request.httpVersion);
    console.log(request.method);
    console.log(request.trailers);
    console.log(request.url);
    // console.log(request.socket.getPeerCertificate()); // Use with HTTPS support only
    request.setTimeout(120000, function () {
        console.log('Client request timeout');
    });
    // request.destroy('my error'); // Работает вместе с request.on('aborted') и request.on('close')
    request.on('aborted', function () {
        console.log('Request has been aborted by the client');
    });
    request.on('close', function () {
        console.log('Underlying connection was closed');
    });
    let clientData = '';
    request.on('data', function (chunk) {
        clientData += chunk;
    });
    request.on('end', function () {
        console.log(request.rawTrailers);
        console.log(clientData);
        response.setTimeout(1200000, function () {
            console.log('Server sockt timeout');
        });
        response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); // Will be merged with any headers passed to response.writeHead()
        console.log('Cookie Header: ' + response.getHeader('Set-Cookie'));
        console.log('Header names: ' + response.getHeaderNames());
        console.log(response.getHeaders());
        if (response.hasHeader('Set-Cookie')) {console.log('Header Set-Cookie set');}
        response.removeHeader('Set-Cookie');
        response.writeContinue(); // Server sends a "100 Continue" HTTP response
        // response.statusCode = 404; // Задачется, если не испоьзуется response.writeHead()
        // response.statusMessage = 'Not found'; // Задачется, если не испоьзуется response.writeHead()
        response.writeHead(200, 'OK', {'Content-Type': 'text/html'}); // Note that 'Content-Length' is given in bytes not characters.
        if (response.headersSent) {console.log('Headers sent');}
        if (response.sendDate) {console.log('Date header sent');}
        response.write('Response from server');
        response.addTrailers({'Content-MD5': '7895bf4b8828b55ceaf47747b4bca667'});
        response.end(); // MUST be called on each response.
        server.close();
    });
    response.on('close', function () {
        console.log('Underlying connection was terminated before response.end() was called or able to flush');
    });
    response.on('finish', function () {
        console.log('Server responce ended');
        if (response.finished) {console.log('Responce finished');}
    });
});

// Используется только, если запрос с типом CONNECT вместо GET или POST
server.on('connect', function (request, clientSocket, head) {
    // Connect to an origin server
    const urlFromClient = url.parse('http://' + request.url);
    const serverSocket = net.connect(urlFromClient.port, urlFromClient.hostname, function () {
        clientSocket.write(
               'HTTP/1.1 200 Connection Established\r\n'
            + 'Proxy-agent: Node.js-Proxy\r\n'
            + '\r\n'
        );
        serverSocket.write(head);
        serverSocket.pipe(clientSocket);
        clientSocket.pipe(serverSocket);
    });
});

// Используется только, если запрос с заголовками 'Connection': 'Upgrade' и 'Upgrade': 'websocket'
server.on('upgrade', function (request, socket, head) {
    socket.write(
           'HTTP/1.1 101 Web Socket Protocol Handshake\r\n'
        + 'Upgrade: WebSocket\r\n'
        + 'Connection: Upgrade\r\n'
        + '\r\n'
    );
    socket.pipe(socket); // echo back
});

// Нужно только, если клиент устанавливает заголовок Expect с 100-continue
server.on('checkContinue', function (request, response) {
    console.log('Server get 100 Continue');
    response.writeContinue();
});

// Нужно только, если клиент устанавливает заголовок Expect не с 100-continue
server.on('checkExpectation', function (request, response) {
    console.log('Emitted each time a request with an HTTP Expect header is received, where the value is not 100-continue');
});

// Нужен если клиент посылает ошибку
server.on('clientError', function (error, socket) {
    console.log('Client emited error');
    socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});

server.on('error', function (error) {
    console.log('Server error: ' + error.message);
});

server.on('close', function () {
    console.log('Server closed');
});

server.listen(8080, '127.0.0.5', function (error) {
    if (error) {throw error;}
    console.log('Server started at 127.0.0.5:8080');
    if (server.listening) {
        console.log('Server is listening');
    }
});

// ============== Client ==============

const options = {
      method: 'GET' // 'POST' // 'CONNECT'
    , protocol: 'http:'
    , auth: 'username:password'
    , hostname: '127.0.0.5'
    , port: 8080
    , path: '/' // 'www.google.com:80'
    , agent: new http.Agent({
                      keepAlive: true // Соединение с сервером должно сохраняться и не разрываться для отправки через него следующих запросов request
                    , keepAliveMsecs: 1000
                    , maxSockets: Infinity
                    , maxFreeSockets: 256
                })
    , headers: {
          'My-Header': 'Hello'
        // , 'Connection': 'Upgrade' // Это заголовок нужен, если нужен upgrade подключения
        // , 'Upgrade': 'websocket' // Это заголовок нужен, если нужен upgrade подключения
      }
    , timeout: 120000
};

const client = http.request(options);

client.once('response', function (response) {
    console.log(response.headers);
    console.log(response.rawHeaders);
    console.log(response.httpVersion);
    console.log(response.statusCode);
    console.log(response.statusMessage);
    console.log(response.trailers);
    response.setEncoding('utf8');
    let serverData = '';
    response.on('data', function (chunk) {
        serverData += chunk;
    });
    response.on('end', function () {
        console.log(serverData);
    });
});

// Используется только, если запрос с типом CONNECT
client.on('connect', function (response, socket, head) {
    console.log('Connect emitted each time a server responds to a request with a CONNECT method.');
    // Make a request over an HTTP tunnel
    socket.on('data', function (chunk) {
        console.log(chunk.toString());
    });
    socket.on('end', function () {
        console.log('Connection to Google closed');
        server.close();
    });
    socket.write(
           'GET / HTTP/1.1\r\n'
        + 'Host: www.google.com:80\r\n'
        + 'Connection: close\r\n'
        + '\r\n'
    );
    socket.end();
});

client.on('socket', function () {
    console.log('Emitted after a socket is assigned to this request.');
});

client.on('abort', function () {
    console.log('Request has been aborted by the client');
});

client.on('aborted', function () {
    console.log('Request has been aborted by the server');
});

// Используется только, если сервер выполнил response.writeContinue()
client.on('continue', function () {
    console.log('Server sends a "100 Continue" HTTP response');
});

// Используется только, если запрос с заголовками 'Connection': 'Upgrade' и 'Upgrade': 'websocket'
client.on('upgrade', function (response, socket, upgradeHead) {
    console.log('Client upgraded');
    socket.end();
    process.exit(0);
});

client.on('error', function (error) {
    console.log('Client error: ' + error.message);
});

client.setHeader('My-Other-Header', 'Hi');
console.log(client.getHeader('My-Header')); // 'Hello'
client.removeHeader('My-Header');

// client.setHeader('Expect', '100-continue'); // Нужно только, если сервер ожидает событие checkContinue
// client.setHeader('Expect', 'not-100-continue'); // Нужно только, если сервер ожидает событие checkExpectation

client.setNoDelay(true);
client.setSocketKeepAlive(true, 1000);
client.setTimeout(10, function () {
    console.log('Client timeout');
});

client.flushHeaders(); // Обычно заголовки и данные упаковываются в единый пакет для отправки. flushHeaders() не деалет эту оптимизацию.

client.write('Client data');

// client.abort();

if (client.aborted) {
    console.log('Client aborted');
}

client.end(); // MUST always call

Комментариев нет:

Отправить комментарий