Ao projetar um serviço da Web RESTful usando HATEOAS, quais são os prós e os contras de mostrar um link como uma URL completa (" http: // servidor: porta / aplicativo / clientes / 1234 ") versus apenas o caminho ("/ aplicativo / clientes / 1234 ")?
Ao projetar um serviço da Web RESTful usando HATEOAS, quais são os prós e os contras de mostrar um link como uma URL completa (" http: // servidor: porta / aplicativo / clientes / 1234 ") versus apenas o caminho ("/ aplicativo / clientes / 1234 ")?
Respostas:
Há uma sutil ambigüidade conceitual quando as pessoas dizem "URI relativo".
Pela definição do RFC3986 , um URI genérico contém:
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
O complicado é que, quando o esquema e a autoridade são omitidos, a parte do "caminho" em si pode ser um caminho absoluto (começa com /
) ou um caminho relativo "sem raiz". Exemplos:
"http://example.com:8042/over/there?name=ferret"
/over/there
here
ou ./here
ou ../here
ou etc.Portanto, se a pergunta for "se um servidor deve produzir um caminho relativo em uma resposta repousante", a resposta é "Não" e o motivo detalhado está disponível aqui . Acho que a maioria das pessoas (inclusive eu) contra "URI relativo" é, na verdade, contra "caminho relativo".
E, na prática, a maioria dos frameworks MVC do lado do servidor pode facilmente gerar URI relativo com caminho absoluto , como /absolute/path/to/the/controller
, e a questão se torna "se a implementação do servidor deve prefixar a scheme://hostname:port
na frente do caminho absoluto". Como a pergunta do OP. Eu não tenho certeza sobre este.
Por um lado, ainda acho que o servidor que retorna um uri completo é recomendado. No entanto, o servidor nuncahostname:port
deve codificar a coisa dentro do código-fonte como este (caso contrário, prefiro recorrer ao uri relativo com caminho absoluto). A solução é o lado do servidor sempre obter esse prefixo do cabeçalho "Host" da solicitação HTTP. Não tenho certeza se isso funciona para todas as situações.
Por outro lado, não parece muito problemático para o cliente concatenar o http://example.com:8042
caminho e o caminho absoluto. Afinal, o cliente já conhece aquele esquema e nome de domínio quando envia a requisição para o servidor certo?
Resumindo, eu diria que recomendo usar URI absoluto, possivelmente fallback para URI relativo com caminho absoluto, nunca use caminho relativo .
Depende de quem está escrevendo o código do cliente. Se você está escrevendo o cliente e o servidor, isso não faz muita diferença. Você sofrerá a dor de construir as URLs no cliente ou no servidor.
No entanto, se você estiver construindo o servidor e espera que outras pessoas escrevam o código do cliente, elas o amarão muito mais se você fornecer URIs completos. Resolver URIs relativos pode ser um pouco complicado. Primeiro, como você os resolve depende do tipo de mídia retornado. Html tem a tag base, o Xml pode ter xml: tags base em cada elemento aninhado, os feeds Atom podem ter uma base no feed e uma base diferente no conteúdo. Se você não fornecer ao seu cliente informações explícitas sobre o URI de base, ele terá que obter o URI de base do URI de solicitação ou talvez do cabeçalho Content-Location! E tome cuidado com essa barra à direita. O URI básico é determinado ignorando todos os caracteres à direita da última barra. Isso significa que a barra final agora é muito significativa ao resolver URIs relativos.
O único outro problema que requer uma pequena menção é o tamanho do documento. Se você estiver retornando uma grande lista de itens em que cada item pode ter vários links, o uso de URLs absolutos pode adicionar uma quantidade significativa de bytes à sua entidade se você não compactar a entidade. Este é um problema de desempenho e você precisa decidir se é significativo caso a caso.
Conforme o seu aplicativo é dimensionado, você pode desejar fazer balanceamento de carga, failover, etc. Se você retornar URIs absolutos, seus aplicativos do lado do cliente seguirão a configuração em evolução dos servidores.
/xxx/yyy...
) e não como significando um URI totalmente qualificado (por exemplo http://api.example.com/xxx/yyy...
).
Usando a tricotomia de RayLou, minha organização optou por favorecer (2). O principal motivo é evitar ataques XSS (Cross-Site Scripting). O problema é que, se um invasor pode injetar sua própria raiz de URL na resposta que vem do servidor, as solicitações subsequentes do usuário (como uma solicitação de autenticação com nome de usuário e senha) podem ser encaminhadas para o próprio servidor do invasor *.
Alguns levantaram a questão de ser capaz de redirecionar solicitações para outros servidores para balanceamento de carga, mas (embora essa não seja minha área de especialização) eu apostaria que há melhores maneiras de habilitar o balanceamento de carga sem ter que redirecionar explicitamente clientes para diferentes hospedeiros.
* por favor, deixe-me saber se há alguma falha nesta linha de raciocínio. O objetivo, claro, não é prevenir todos os ataques, mas pelo menos uma via de ataque.
Você deve sempre usar o URL completo. Ele atua como o identificador exclusivo para o recurso, pois todos os URLs devem ser exclusivos.
Eu também diria que você deve ser consistente. Como o cabeçalho Location HTTP espera um URL completo com base na especificação HTTP, o URL completo é enviado de volta no cabeçalho Location para o cliente quando um novo recurso é criado. Seria estranho para você fornecer um URL completo no cabeçalho Location e, em seguida, URIs relativos nos links dentro do corpo de sua resposta.
Location
cabeçalho da especificação fornece - um URI absoluto que não contém o esquema de URI ou o local de rede do servidor. Embora links e IDs sejam frequentemente confundidos, eles não são a mesma coisa - o primeiro tem contexto, o último não.
Uma consideração importante em grandes resultados de API é a sobrecarga de rede extra de incluir o URI completo repetidamente. Acredite ou não, o gzip não resolve totalmente esse problema (não sei por quê). Ficamos chocados com a quantidade de espaço que o URI completo ocupou quando havia centenas de links incluídos em um resultado.
Uma desvantagem de usar URIs absolutos é que a API não pode ser proxy.
Retire ... não é verdade. Você deve ir para um URL completo, incluindo o domínio.
Em relação aos profissionais, vejo a redução de bytes a serem transmitidos em detrimento do manuseio extra exigido por um cliente para o caminho (absoluto). Se você está desesperado para salvar cada byte, mesmo depois de tentar a codificação de conteúdo como gzip, uso adequado de cabeçalhos de cache, uso de etags e solicitações condicionais no cliente, então isso pode ser necessário no final, mas espero retornos muito maiores em seus esforços em outro lugar.
Em relação aos contras, vejo uma perda de controle sobre como você pode direcionar o fluxo de clientes entre recursos no futuro (balanceamento de carga, teste A / B, ...) e consideraria uma prática ruim em relação ao gerenciamento de uma web API. A URL que você fornece não é mais basicamente opaca para o cliente (consulte Tim Berners-Lee Axiomas de Arquitetura da Web sobre opacidade de URI ). No final, você se torna responsável por manter os clientes satisfeitos em relação ao uso criativo de sua API, mesmo que seja apenas em relação à estrutura de seu espaço de URL. Se você precisar permitir uma modificação de URL explicitamente definida, considere o uso de modelos de URI conforme usados na linguagem de aplicativo de hipertexto .