O que é o middleware Rack no Ruby? Não consegui encontrar nenhuma boa explicação para o que eles querem dizer com "middleware".
ruby-on-rails
ruby
http
web-applications
rack
chrisgoyal
fonte
fonte
Respostas:
Rack como Design
O middleware do rack é mais do que "uma maneira de filtrar uma solicitação e resposta" - é uma implementação do padrão de design de pipeline para servidores da Web que usam o Rack .
Ele separa de maneira muito clara as diferentes etapas do processamento de uma solicitação - a separação de preocupações é um objetivo principal de todos os produtos de software bem projetados.
Por exemplo, com o Rack, posso ter estágios separados do pipeline executando:
Autenticação : quando a solicitação chega, os detalhes de logon do usuário estão corretos? Como validar esse OAuth, autenticação básica HTTP, nome / senha?
Autorização : "o usuário está autorizado a executar esta tarefa específica?", Ou seja, segurança baseada em função.
Armazenamento em cache : já processei essa solicitação, posso retornar um resultado em cache?
Decoração : como posso melhorar a solicitação para melhorar o processamento a jusante?
Monitoramento de desempenho e uso : quais estatísticas posso obter da solicitação e resposta?
Execução : efetue o tratamento da solicitação e forneça uma resposta.
Ser capaz de separar os diferentes estágios (e opcionalmente incluí-los) é uma grande ajuda no desenvolvimento de aplicativos bem estruturados.
Comunidade
Há também um ótimo ecossistema em desenvolvimento no Rack Middleware - você deve encontrar componentes de rack pré-criados para executar todas as etapas acima e muito mais. Consulte o wiki do Rack GitHub para obter uma lista do middleware .
O que é Middleware?
Middleware é um termo terrível que se refere a qualquer componente / biblioteca de software que ajude, mas não esteja diretamente envolvido na execução de alguma tarefa. Exemplos muito comuns são log, autenticação e outros componentes de processamento horizontal comuns . Essas tendem a ser as coisas que todos precisam em vários aplicativos, mas muitas pessoas não estão interessadas (ou deveriam estar) em se desenvolver.
Mais Informações
O comentário sobre como ser uma maneira de filtrar solicitações provavelmente vem do elenco da tela do episódio 151 do RailsCast: Rack Middleware .
O middleware do rack foi desenvolvido a partir do rack e há uma excelente introdução ao Introdução ao middleware do rack .
Há uma introdução ao middleware na Wikipedia aqui .
fonte
Primeiro de tudo, o Rack é exatamente duas coisas:
Rack - a interface do servidor da Web
O básico do rack é uma convenção simples. Todo servidor da web compatível com rack sempre chama um método de chamada em um objeto que você fornece a ele e serve o resultado desse método. O rack especifica exatamente como esse método de chamada deve ser e o que ele deve retornar. Isso é tortura.
Vamos fazer uma tentativa simples. Usarei o WEBrick como servidor da web compatível com rack, mas qualquer um deles o fará. Vamos criar um aplicativo Web simples que retorne uma sequência JSON. Para isso, criaremos um arquivo chamado config.ru. O config.ru será chamado automaticamente pelo conjunto de comandos da gem do rack, que simplesmente executará o conteúdo do config.ru em um servidor da web compatível com rack. Então, vamos adicionar o seguinte ao arquivo config.ru:
Como a convenção especifica, nosso servidor possui um método chamado call que aceita um hash do ambiente e retorna uma matriz com o formato [status, headers, body] para o servidor da web servir. Vamos testá-lo simplesmente chamando de rackup. Um servidor compatível com rack padrão, talvez o WEBrick ou Mongrel seja iniciado e aguarde imediatamente a entrega das solicitações.
Vamos testar nosso novo servidor JSON, curvando ou visitando o URL
http://localhost:9292/hello.json
e voila:Funciona. Ótimo! Essa é a base para todo framework web, seja Rails ou Sinatra. Em algum momento, eles implementam um método de chamada, trabalham com todo o código da estrutura e, finalmente, retornam uma resposta na forma típica [status, headers, body].
No Ruby on Rails, por exemplo, as solicitações de rack atingem a
ActionDispatch::Routing.Mapper
classe que se parece com isso:Então, basicamente, o Rails verifica, dependendo do hash env, se alguma rota corresponder. Nesse caso, ele passa o hash env para o aplicativo para calcular a resposta, caso contrário, ele responde imediatamente com um 404. Portanto, qualquer servidor da Web que seja compatível com a convenção de interface do rack poderá atender a um aplicativo Rails totalmente desenvolvido.
Middleware
O rack também suporta a criação de camadas de middleware. Eles basicamente interceptam uma solicitação, fazem algo com ela e a transmitem. Isso é muito útil para tarefas versáteis.
Digamos que queremos adicionar log ao nosso servidor JSON que também mede quanto tempo uma solicitação leva. Podemos simplesmente criar um registrador de middleware que faça exatamente isso:
Quando é criado, ele salva uma cópia do aplicativo real do rack. No nosso caso, é uma instância do nosso JSONServer. O rack chama automaticamente o método de chamada no middleware e espera retornar uma
[status, headers, body]
matriz, assim como nosso JSONServer retorna.Portanto, nesse middleware, o ponto de partida é adotado, a chamada real para o JSONServer é feita
@app.call(env)
e o logger gera a entrada de log e, finalmente, retorna a resposta como[@status, @headers, @body]
.Para fazer nosso pequeno rackup.ru usar esse middleware, adicione um RackLogger de uso como este:
Reinicie o servidor e pronto, ele gera um log em cada solicitação. O rack permite adicionar vários middlewares chamados na ordem em que são adicionados. É apenas uma ótima maneira de adicionar funcionalidade sem alterar o núcleo do aplicativo em rack.
Rack - A jóia
Embora o rack - antes de tudo - seja uma convenção, ele também é uma jóia que fornece ótima funcionalidade. Um deles já usamos para o nosso servidor JSON, o comando rackup. Mas tem mais! A jóia do rack fornece pequenos aplicativos para muitos casos de uso, como servir arquivos estáticos ou mesmo diretórios inteiros. Vamos ver como servimos um arquivo simples, por exemplo, um arquivo HTML muito básico localizado em htmls / index.html:
Talvez desejemos servir esse arquivo a partir da raiz do site, então vamos adicionar o seguinte ao nosso config.ru:
Se o visitarmos
http://localhost:9292
, veremos nosso arquivo html perfeitamente renderizado. Isso foi fácil, certo?Vamos adicionar um diretório inteiro de arquivos javascript, criando alguns arquivos javascript em / javascripts e adicionando o seguinte ao config.ru:
Reinicie o servidor e visite
http://localhost:9292/javascript
e você verá uma lista de todos os arquivos javascript que você pode incluir agora diretamente de qualquer lugar.fonte
Eu tive um problema para entender o Rack por um bom tempo. Eu só o entendi completamente depois de trabalhar na criação desse servidor Web em miniatura Ruby . Compartilhei meus aprendizados sobre o Rack (na forma de uma história) aqui no meu blog: http://gauravchande.com/what-is-rack-in-ruby-rails
O feedback é mais que bem-vindo.
fonte
config.ru
exemplo executável mínimoCorra
rackup
e visitelocalhost:9292
. A saída é:Portanto, é claro que o
Middleware
embrulho e chama o aplicativo principal. Portanto, ele pode pré-processar a solicitação e pós-processar a resposta de qualquer maneira.Conforme explicado em: http://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack , o Rails usa middlewares de rack para muitas funcionalidades, e você também pode adicionar
config.middleware.use
os métodos da família.A vantagem de implementar a funcionalidade em um middleware é que você pode reutilizá-la em qualquer estrutura Rack, portanto, todas as principais Ruby, e não apenas Rails.
fonte
O middleware em rack é uma maneira de filtrar uma solicitação e resposta que entra no seu aplicativo. Um componente de middleware fica entre o cliente e o servidor, processando solicitações de entrada e respostas de saída, mas é mais do que uma interface que pode ser usada para conversar com o servidor da web. É usado para agrupar e solicitar módulos, que geralmente são classes Ruby, e especificar a dependência entre elas. O módulo de middleware do rack deve apenas: - ter o construtor que leva o próximo aplicativo na pilha como parâmetro - responder ao método "call", que usa o hash do ambiente como parâmetro. O retorno do valor desta chamada é uma matriz de: código de status, hash do ambiente e corpo da resposta.
fonte
Eu usei o middleware Rack para resolver alguns problemas:
Forneceu correções bastante elegantes em ambos os casos.
fonte
O que é Rack?
O rack fornece uma interface mínima entre os servidores da web que suportam as estruturas Ruby e Ruby.
Usando o Rack, você pode escrever um Aplicativo de Rack.
O rack transmitirá o hash do ambiente (um Hash, contido em uma solicitação HTTP de um cliente, que consiste em cabeçalhos semelhantes a CGI) para o aplicativo de rack, que pode usar as coisas contidas nesse hash para fazer o que quiser.
O que é um aplicativo de rack?
Para usar o Rack, você deve fornecer um 'aplicativo' - um objeto que responda ao
#call
método com o Hash do ambiente como parâmetro (normalmente definido comoenv
).#call
deve retornar uma matriz de exatamente três valores:each
).Você pode escrever um aplicativo de rack que retorne essa matriz - isso será enviado de volta ao seu cliente, pelo rack, dentro de uma resposta (na verdade, essa é uma instância da classe
Rack::Response
[clique para acessar a documentação]).Uma aplicação de rack muito simples:
gem install rack
config.ru
arquivo - o Rack sabe procurar por isso.Criaremos um pequeno aplicativo de rack que retornará uma resposta (uma instância de
Rack::Response
) cujo corpo de resposta seja uma matriz que contenha uma String:"Hello, World!"
.Iniciaremos um servidor local usando o comando
rackup
.Ao visitar a porta relevante em nosso navegador, veremos "Olá, mundo!" renderizado na janela de exibição.
Inicie um servidor local
rackup
e visite localhost: 9292 e você verá 'Olá, mundo!' prestados.Essa não é uma explicação abrangente, mas essencialmente o que acontece aqui é que o Cliente (o navegador) envia uma Solicitação HTTP ao Rack, através do servidor local, e o Rack instancia
MessageApp
e executacall
, passando o Environment Hash como parâmetro para o método ( oenv
argumento).O rack pega o valor de retorno (a matriz) e o usa para criar uma instância
Rack::Response
e envia de volta ao cliente. O navegador usa magia para imprimir 'Hello, World!' para a tela.Aliás, se você quiser ver como é o hash do ambiente, basta colocar
puts env
embaixodef call(env)
.Por menor que seja, o que você escreveu aqui é um aplicativo Rack!
Fazendo um aplicativo de rack interagir com o hash do ambiente de entrada
Em nosso pequeno aplicativo Rack, podemos interagir com o
env
hash (veja aqui mais sobre o hash do ambiente).Implementaremos a capacidade do usuário inserir sua própria string de consulta na URL; portanto, essa string estará presente na solicitação HTTP, encapsulada como um valor em um dos pares de chave / valor do hash do ambiente.
Nosso aplicativo Rack acessará essa sequência de consultas no hash Environment e a enviará de volta ao cliente (nosso navegador, neste caso) por meio do Corpo na resposta.
Dos documentos do rack sobre a Hash do ambiente: "QUERY_STRING: a parte do URL da solicitação que segue o?, Se houver. Pode estar vazia, mas é sempre necessária!"
Agora,
rackup
visitelocalhost:9292?hello
(?hello
sendo a string de consulta) e você verá 'olá' processado na janela de exibição.Rack Middleware
Nós vamos:
MessageSetter
,env
,MessageSetter
irá inserir uma'MESSAGE'
chave no hash env, seu valor sendo'Hello, World!'
seenv['QUERY_STRING']
estiver vazio;env['QUERY_STRING']
se não,@app.call(env)
-@app
ser o próximo aplicativo na 'pilha':MessageApp
.Primeiro, a versão 'mão longa':
Nos documentos do Rack :: Builder , vemos que
Rack::Builder
implementa um pequeno DSL para construir iterativamente aplicativos de rack. Isso basicamente significa que você pode criar uma 'Pilha' consistindo em um ou mais Middlewares e um aplicativo 'nível inferior' para o qual enviar. Todas as solicitações enviadas ao seu aplicativo de nível inferior serão processadas primeiro pelo (s) seu (s) Middleware (s).#use
especifica o middleware a ser usado em uma pilha. Leva o middleware como argumento.O Middleware do rack deve:
call
método que usa o hash do ambiente como parâmetro.No nosso caso, o 'Middleware' é
MessageSetter
, o 'construtor' é oinitialize
método do MessageSetter , o 'próximo aplicativo' na pilha éMessageApp
.Então, aqui, por causa do que
Rack::Builder
faz sob o capô, oapp
argumento deMessageSetter
'sinitialize
método éMessageApp
.(contorne o item acima antes de prosseguir)
Portanto, cada parte do Middleware basicamente 'transmite' o hash de ambiente existente para o próximo aplicativo na cadeia - para que você tenha a oportunidade de alterar esse hash de ambiente no Middleware antes de passá-lo para o próximo aplicativo na pilha.
#run
aceita um argumento que é um objeto que responde#call
e retorna uma resposta em rack (uma instância deRack::Response
).Conclusões
Usando
Rack::Builder
você pode construir cadeias de Middlewares e qualquer solicitação para seu aplicativo será processada por cada Middleware, por sua vez, antes de finalmente ser processada pela parte final da pilha (no nosso casoMessageApp
). Isso é extremamente útil porque separa diferentes estágios dos pedidos de processamento. Em termos de 'separação de preocupações', não poderia ser muito mais limpo!Você pode construir um 'pipeline de solicitação' que consiste em vários Middlewares que lidam com coisas como:
(pontos de marcador acima de outra resposta neste tópico)
Você verá isso frequentemente em aplicativos profissionais do Sinatra. Sinatra usa Rack! Veja aqui a definição do que Sinatra é!
Como observação final,
config.ru
podemos escrever em estilo abreviado, produzindo exatamente a mesma funcionalidade (e é isso que você normalmente verá):E para mostrar mais explicitamente o que
MessageApp
está fazendo, aqui está sua versão de 'mão longa' que mostra explicitamente que#call
está criando uma nova instância deRack::Response
, com os três argumentos necessários.Links Úteis
fonte
Rack - a interface entre o servidor de aplicativos e a Web
Rack é um pacote Ruby que fornece uma interface para um servidor web se comunicar com o aplicativo. É fácil adicionar componentes de middleware entre o servidor da Web e o aplicativo para modificar a maneira como sua solicitação / resposta se comporta. O componente de middleware fica entre o cliente e o servidor, processando solicitações de entrada e respostas de saída.
Em palavras leigas, é basicamente apenas um conjunto de diretrizes sobre como um servidor e um aplicativo Rails (ou qualquer outro aplicativo da web Ruby) devem conversar entre si .
Para usar o Rack, forneça um "aplicativo": um objeto que responda ao método de chamada, usando o hash do ambiente como parâmetro e retornando uma matriz com três elementos:
Para mais explicações, você pode seguir os links abaixo.
No rails, temos o config.ru como um arquivo em rack, você pode executar qualquer arquivo em rack com o
rackup
comando E a porta padrão para isso é9292
. Para testar isso, você pode simplesmente rodarrackup
no diretório rails e ver o resultado. Você também pode atribuir a porta na qual deseja executá-la. O comando para executar o arquivo em rack em qualquer porta específica éfonte
Rack é uma jóia que fornece uma interface simples para abstrair a solicitação / resposta HTTP. O rack fica entre estruturas da web (Rails, Sinatra etc.) e servidores da web (unicórnio, puma) como um adaptador. Da imagem acima, isso mantém o servidor unicórnio completamente independente de saber sobre trilhos e os trilhos não sabem sobre unicórnio. Este é um bom exemplo de acoplamento solto , separação de preocupações .
A imagem acima é desta palestra da conferência sobre trilhos no rack https://youtu.be/3PnUV9QzB0g Eu recomendo assistir para um entendimento mais profundo.
fonte