Desenvolvimento

12 jan, 2016

Fazendo log com requisições POST usando websockets

Publicidade

Tenho trabalhado com um background de geolocalização com uma aplicação Ionic. Tem um plugin bem bacana para fazer isso. A versão gratuita do plugin é ok, mas na versão premium você tem várias melhorias, especialmente no consumo de bateria de dispositivos Android.

Basicamente o plugin faz uma requisição POST para o servidor com o dado do GPS. Quando eu estava desenvolvendo minha aplicação, precisava de um simples servidor HTTP para ver as requisições POST. Depois, eu faria o código do backend para manipular as requisições. Eu posso desenvolver uma simples aplicação Silex com uma rota POST e fazer o log da requisição em um arquivo, ou fazer um flush das requisições para o console. Isso teria sido simples, mas como eu sou um grande fã de websockets (sim, eu tenho que admitir que eu quero usar websockets em todo lugar!) eu tive uma ideia: criar um simples servidor HTTP para manipular minhas requisições POST GPS, mas, em vez de fazer o log na requisição, eu emitiria um websocket. Então, eu posso criar um site que se conecta ao servidor websocket e registrar na tela a requisição POST. Ok, hoje eu estou meio devagar para lutar com o frontend, então meu log será no console do browser.

Para construir a aplicação, eu vou reutilizar um dos meus projetos no GitHub: PHP dumper. A ideia é quase a mesma. Vou criar um servidor HTTP simples com Silex com duas rotas, uma para lidar com requisições POST (as do GPS) e outra para o GET, para me permitir conectar ao websocket.

Esse é o servidor. Silex, um pouco de Twig, um pouco também de Guzzle, e é isto:

use GuzzleHttp\Client;
use Silex\Application;
use Silex\Provider\TwigServiceProvider;
use Symfony\Component\HttpFoundation\Request;
 
$app = new Application([
    'debug'       => true,
    'ioServer'    => '//localhost:8888',
    'wsConnector' => 'http://127.0.0.1:26300'
]);
 
$app->register(new TwigServiceProvider(), [
    'twig.path' => __DIR__ . '/../views',
]);
 
$app['http.client'] = new Client();
 
$app->get("/{channel}", function (Application $app, $channel) {
    return $app['twig']->render('index.twig', [
        'channel'  => $channel,
        'ioServer' => $app['ioServer']
    ]);
});
 
$app->post("/{channel}", function (Application $app, $channel, Request $request) {
    $app['http.client']->get($app['wsConnector'] . "/info/{$channel}/" . json_encode($request->getContent()));
 
    return $app->json('OK');
});
 
$app->run();

Esse é o template Twig. Nada de especial: um pouco de Bootstrap e um cliente socket.io. Cada vez que o usuário acessa a url de um “canal” (GET/mychannel), ele faz a conexão com o servidor websocket.

var CONF = {
        IO: {HOST: '0.0.0.0', PORT: 8888},
        EXPRESS: {HOST: '0.0.0.0', PORT: 26300}
    },
    express = require('express'),
    expressApp = express(),
    server = require('http').Server(expressApp),
    io = require('socket.io')(server, {origins: 'localhost:*'})
    ;
 
expressApp.get('/:type/:session/:message', function (req, res) {
    console.log(req.params);
    var session = req.params.session,
        type = req.params.type,
        message = req.params.message;
 
    io.sockets.emit('dumper.' + session, {title: type, data: JSON.parse(message)});
    res.json('OK');
});
 
io.sockets.on('connection', function (socket) {
    console.log("Socket connected!");
});
 
expressApp.listen(CONF.EXPRESS.PORT, CONF.EXPRESS.HOST, function () {
    console.log('Express started');
});
 
server.listen(CONF.IO.PORT, CONF.IO.HOST, function () {
    console.log('IO started');
});

Cada vez que o plugin de geolocalização enviar o POST com dados de GPS, o roteador de POST do Silex irá emitir o WebSocket para o canal desejado. Nosso cliente Websocket apenas irá locar os dados GPS utilizando console.log. É difícil explicar, mas é um procedimento bastante simples.

Também é possível emular as requisições POST com este simples script node:

var request = require('request');
 
request.post('http://localhost:8080/Hello', {form: {key: 'value'}}, function (error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body)
    }
});

E é isso. Você pode ver o código completo no meu GitHub.

***

Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://gonzalo123.com/2015/11/16/post-request-logger-using-websockets/