Dev (Back & Front)

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/