Cabeçalhos HTTP personalizados: convenções de nomenclatura

1115

Vários de nossos usuários nos pediram para incluir dados relativos à sua conta nos cabeçalhos HTTP das solicitações que enviamos a eles, ou mesmo nas respostas que eles recebem da nossa API. Qual é a convenção geral para adicionar cabeçalhos HTTP personalizados, em termos de nomeação , formato ... etc.

Além disso, fique à vontade para postar qualquer uso inteligente desses que você encontrou na Web; Estamos tentando implementar isso usando o que há de melhor como um alvo :)

Julien Genestoux
fonte
25
Esteja ciente de que os firewalls podem remover os campos do cabeçalho de resposta. Alguns removem tudo o que não é mencionado na RFC 2616 (junho de 1999, HTTP 1.1). O lado do cliente ainda deve ser utilizável sem os novos campos.
Stesch 9/04
5
Note que o comentário de @stesch não se aplica quando se usa HTTP S .
code_dredd
1
Observe que o comentário de @code_dredd é uma lenda urbana. Os firewalls podem filtrar o conteúdo HTTPS. Veja howtoforge.com/filtering-https-traffic-with-squid e watchguard.com/help/docs/wsm/xtm_11/en-us/content/en-us/…
stesch em
@stesch Dado que seu artigo basicamente transforma o proxy em algo semelhante a um MiTM (ele pega uma conexão de cliente criptografada e cria uma nova), então você pode fazer quase tudo, mas esse fato nega a criptografia do PoV do proxy b / c descriptografar o próprio conteúdo do cliente. Nesse caso, a partir PoV do proxy, é basicamente como se você não estivesse usando HTTPS no 1º lugar ...
code_dredd

Respostas:

1172

A recomendação é era para começar seu nome com "X-". Por exemplo X-Forwarded-For, X-Requested-With. Isso também é mencionado na seção 5 da RFC 2047 .


Atualização 1 : em junho de 2011, o primeiro rascunho da IETF foi publicado para descontinuar a recomendação do uso do prefixo "X-" para cabeçalhos fora do padrão. A razão é que quando cabeçalhos não padronizados prefixados com "X-" se tornar padrão, remover a compatibilidade "X-" prefixo breaks para trás, forçando protocolos de aplicação para apoiar os dois nomes (por exemplo, x-gzipe gzipsão agora equivalentes). Portanto, a recomendação oficial é apenas nomeá-los com sensatez sem o prefixo "X-".


Atualização 2 : em junho de 2012, a descontinuação da recomendação de uso do prefixo "X-" tornou-se oficial como RFC 6648 . Abaixo estão citações de relevância:

3. Recomendações para criadores de novos parâmetros

...

  1. NÃO DEVE prefixar seus nomes de parâmetro com "X-" ou construções semelhantes.

4. Recomendações para designers de protocolo

...

  1. NÃO DEVE proibir que parâmetros com um prefixo "X-" ou construções semelhantes sejam registrados.

  2. NÃO DEVE estipular que um parâmetro com um prefixo "X-" ou construções semelhantes precisa ser entendido como não padronizado.

  3. NÃO DEVE estipular que um parâmetro sem um prefixo "X-" ou construções semelhantes precise ser entendido como padronizado.

Observe que "NÃO DEVE" ("desencorajado") não é o mesmo que "NÃO DEVE" ("proibido"); consulte também a RFC 2119 para obter outras especificações sobre essas palavras-chave. Em outras palavras, você pode continuar usando os cabeçalhos com prefixo "X-", mas isso não é mais recomendado oficialmente e você definitivamente não pode documentá-los como se fossem padrão público.


Resumo :

  • a recomendação oficial é apenas nomeá-los com sensatez sem o prefixo "X-"
  • você pode continuar usando os cabeçalhos com prefixo "X-", mas não é mais recomendado oficialmente e você definitivamente não pode documentá-los como se fossem padrão público
BalusC
fonte
306
Assim como existem muitas crianças que nunca acabam como atletas profissionais, muitos cabeçalhos personalizados nunca acabam como padrões. Estou inclinado a manter o "X-" neles.
G-Mac
19
@ G-Mac concordou. Há assim muitos cabeçalhos personalizados que nunca vai acabar padronizados. Os poucos que fazem isso, é fácil apenas editar seu código de if (header == "x-gzip")para if (header == "x-gzip" || header == "gzip"). Quanto à sua analogia, aqui está outra: é como o ditado militar "Oh, é problemático mudar alguém de particular para general. Então, de agora em diante, todos vocês são generais. Agora não precisamos fazer tanto trabalho"
Cole Johnson
24
@ColeJohnson Não tenho certeza se essa analogia funciona. O problema aqui é que não há um ponto central para alterar o nome. Todo trecho de código que espera que o x-gzip agora precise ser alterado ou o cabeçalho antigo precisa continuar sendo usado além do novo. É preferível ir com RFC 6648.
vinod
4
@Vinod yes. Faz sentido, mas há tantos padrões propostos que nunca verão a luz do dia. Para tipos de arquivo, com certeza; solte o X-prefixo. Sou contra, mas vá em frente e faça. Para cabeçalhos OTOH, não o deixe cair. Torna fácil olhar e dizer: "oh, não é padrão; eu posso ignorá-lo" vs "existem aqueles X-cabeçalhos fora do padrão , e há um que não reconheço; posso ignorá-lo com segurança?"
Cole Johnson
21
Embora o tom da resposta semanal seja desnecessariamente defensivo, acredito que ele esteja certo, e seu argumento resolve o problema ilustrado neste tópico de comentário. Em resumo, não tente identificar se um cabeçalho será "graduado" ou não; em vez disso, determine se é um cabeçalho público ou privado (específico do aplicativo ou "genérico" / "global"). Para cabeçalhos privados, use opcionalmente X-para garantir que não haja conflito com cabeçalhos públicos (graças ao RFC6648, que trata de cabeçalhos públicos) e, além disso, use definitivamente um prefixo privado arbitrário. Para cabeçalhos públicos, não use X-em nenhuma circunstância.
12/12/14
535

A questão merece ser relida. A pergunta real não é semelhante aos prefixos do fornecedor nas propriedades CSS, onde a prova de futuro e o pensamento sobre o suporte do fornecedor e os padrões oficiais são adequados. A pergunta real é mais semelhante à escolha de nomes de parâmetros de consulta de URL. Ninguém deve se importar com o que são. Mas espaçar o nome dos personalizados é algo perfeitamente válido - e comum e correto - a ser feito.

Justificativa:
trata-se de convenções entre desenvolvedores para cabeçalhos personalizados específicos de aplicativos - " dados relevantes para sua conta " - que não têm nada a ver com fornecedores, organismos de padrões ou protocolos a serem implementados por terceiros, exceto que o desenvolvedor a questão simplesmente precisa evitar nomes de cabeçalho que possam ter outro uso pretendido por servidores, proxies ou clientes. Por esse motivo, os exemplos "X-Gzip / Gzip" e "X-Forwarded-For / Forwarded-For" apresentados são discutíveis. A questão colocada é sobre convenções no contexto de uma API privada, semelhante às convenções de nomenclatura de parâmetros de consulta de URL. É uma questão de preferência e espaçamento entre nomes; preocupações quanto ao "X-ClientDataFoo" ser suportado por qualquer proxy ou fornecedor sem o "X"

Não há nada de especial ou mágico no prefixo "X-", mas ajuda a deixar claro que é um cabeçalho personalizado. De fato, a RFC-6648 et al ajudam a reforçar o argumento do uso de um prefixo "X-", porque - como os fornecedores de clientes e servidores HTTP abandonam o prefixo - a API privada, a API privada e os dados pessoais do aplicativo. O mecanismo de passagem está se tornando ainda mais isolado contra colisões de espaço de nome com o pequeno número de nomes de cabeçalho reservados oficiais. Dito isto, minha preferência e recomendação pessoal é ir além e fazer, por exemplo, "X-ACME-ClientDataFoo" (se sua empresa de widgets for "ACME").

IMHO, a especificação da IETF é insuficientemente específica para responder à pergunta do OP, porque não consegue distinguir entre casos de uso completamente diferentes: (A) fornecedores que introduzem novos recursos globalmente aplicáveis, como "Forwarded-For", por um lado, vs. (B) desenvolvedores de aplicativos que transmitem seqüências específicas de aplicativos para / do cliente e servidor. A especificação refere-se apenas ao primeiro, (A). A questão aqui é se existem convenções para (B). Tem. Elas envolvem agrupar os parâmetros em ordem alfabética e separá-los dos vários cabeçalhos relevantes ao padrão do tipo (A). O uso do prefixo "X-" ou "X-ACME-" é conveniente e legítimo para (B) e não entra em conflito com (A). Quanto mais fornecedores deixarem de usar "X-" para (A), mais distintos serão (B).

Exemplo: o
Google (que carrega um pouco de peso nos vários corpos de padrões) - atualmente, 20141102 nesta ligeira edição da minha resposta - atualmente usa "X-Mod-Pagespeed" para indicar a versão do módulo Apache envolvido na transformação de uma dada resposta. Alguém está realmente sugerindo que o Google use "Mod-Pagespeed", sem o "X-", e / ou peça à IETF para abençoar seu uso?

Resumo:
se você estiver usando cabeçalhos HTTP personalizados (como uma alternativa às vezes apropriada para cookies) em seu aplicativo para passar dados para / do seu servidor, e esses cabeçalhos, explicitamente, NÃO devem ser usados ​​fora do contexto de seu aplicativo, espaçá-los com um prefixo "X-" ou "X-FOO-" é uma convenção razoável e comum.

semanalmente
fonte
52
Eu apreciaria se algum defensor do meu comentário pudesse explicar que parte da minha resposta eles acham censurável. Não me importo muito com a minha pontuação de reputação, mas estou genuinamente curioso. Onde está o desacordo? Obrigado.
Cweekly 30/10/2013
56
Concordo plenamente com a sua resposta e é a única resposta aqui que responde à pergunta real. Estamos falando de cabeçalhos personalizados, específicos de aplicativos aqui, para nunca serem padronizados nos padrões HTTP. Existe uma convenção comum para esses que as pessoas tendem a usar? (como prefixo-los com "_" talvez isto é: ( "_ClientDataFoo")?
Marchy
14
Obrigado Marchy, sim, a resposta aceita não aborda a pergunta. A descontinuação da IETF do prefixo "X-" para cabeçalhos não padrão (mas genéricos) é irrelevante para cabeçalhos específicos de aplicativos personalizados que nunca serão padronizados. Para responder sua pergunta, na minha opinião e experiência (16 anos de webdev), a melhor convenção é usar o "X-ACME-ClientData" mencionado acima. "X-" bc não é padrão (nem nunca será, e é por isso que a depreciação da IETF é discutida aqui), "ACME-" para nomear o espaço para sua empresa "ACME" ou aplicativo específico, e "ClientData" pode ser o que for nome semântico que você gosta. :)
cweekly
5
@DarrelMiller ... daí a recomendação de usar o X-ACMECO-WIDGET-FOO. Insisto que, para a pergunta do OP, como solicitado, o uso de X- simplesmente não é contra-indicado pela RFC-6648 e similares. Se você é um fornecedor que fornece uma estrutura, biblioteca ou módulo para uso em projetos de outras pessoas, essa é uma história diferente e, por todos os meios, siga essa RFC até um T. as convenções de nomenclatura de cabeçalho específicas do aplicativo são efetivamente APIs completamente privadas. Como eles se chocariam com os nomes de "todos os outros"? De quem seriam esses?
cweekly
11
Sinceramente, estou tendo um pouco de dificuldade para entender o raciocínio da RFC. Concedido que, se e quando o parâmetro for padronizado, haverá versões x e não-x. Isso é apenas um problema se o comportamento das versões x e não x é idêntico. Tropecei aqui porque estou olhando para adicionar um cabeçalho "em nome de" à minha API. Pode se tornar público algum dia (como é um tipo comum de caso de uso). Se eu usei "On-Behalf-Of" e algum dia eles adicionam isso como cabeçalho padrão, quais são as chances de que minha semântica seja idêntica à padronizada?
Fool4jesus
62

O formato para cabeçalhos HTTP é definido na especificação HTTP. Vou falar sobre o HTTP 1.1, para o qual a especificação é RFC 2616 . Na seção 4.2, 'Cabeçalhos da mensagem', a estrutura geral de um cabeçalho é definida:

   message-header = field-name ":" [ field-value ]
   field-name     = token
   field-value    = *( field-content | LWS )
   field-content  = <the OCTETs making up the field-value
                    and consisting of either *TEXT or combinations
                    of token, separators, and quoted-string>

Essa definição se baseia em dois pilares principais, token e TEXT. Ambos são definidos na seção 2.2, 'Regras básicas'. O token é:

   token          = 1*<any CHAR except CTLs or separators>

Por sua vez, apoiando-se no CHAR, CTL e nos separadores:

   CHAR           = <any US-ASCII character (octets 0 - 127)>

   CTL            = <any US-ASCII control character
                    (octets 0 - 31) and DEL (127)>

   separators     = "(" | ")" | "<" | ">" | "@"
                  | "," | ";" | ":" | "\" | <">
                  | "/" | "[" | "]" | "?" | "="
                  | "{" | "}" | SP | HT

TEXTO é:

   TEXT           = <any OCTET except CTLs,
                    but including LWS>

Onde LWS é um espaço em branco linear, cuja definição eu não reproduzirei, e OCTET é:

   OCTET          = <any 8-bit sequence of data>

Há uma nota que acompanha a definição:

The TEXT rule is only used for descriptive field contents and values
that are not intended to be interpreted by the message parser. Words
of *TEXT MAY contain characters from character sets other than ISO-
8859-1 [22] only when encoded according to the rules of RFC 2047
[14].

Então, duas conclusões. Em primeiro lugar, fica claro que o nome do cabeçalho deve ser composto de um subconjunto de caracteres ASCII - alfanuméricos, alguma pontuação, não muito mais. Segundo, não há nada na definição de um valor de cabeçalho que o restrinja a ASCII ou exclua caracteres de 8 bits: ele é explicitamente composto por octetos, com apenas caracteres de controle barrados (observe que CR e LF são considerados controles). Além disso, o comentário sobre a produção TEXT implica que os octetos devem ser interpretados como estando na ISO-8859-1 e que existe um mecanismo de codificação (que é horrível, aliás) para representar caracteres fora dessa codificação.

Portanto, para responder ao @BalusC em particular, é bastante claro que, de acordo com a especificação, os valores do cabeçalho estão na ISO-8859-1. Enviei caracteres 8859-1 (especificamente, algumas vogais acentuadas usadas em francês) em um cabeçalho do Tomcat e as interpretei corretamente pelo Firefox; portanto, até certo ponto, isso funciona tanto na prática quanto na teoria. (embora esse fosse um cabeçalho de local, que contém um URL e esses caracteres não sejam legais nos URLs, isso era ilegal, mas com uma regra diferente!).

Dito isto, eu não confiaria no funcionamento da ISO-8859-1 em todos os servidores, proxies e clientes; portanto, continuaria com o ASCII como uma questão de programação defensiva.

Tom Anderson
fonte
3
A especificação HTTP mais recente RFC7230 diz "Os campos de cabeçalho recém-definidos DEVEM limitar seus valores de campo a octetos US-ASCII".
Robert Tupelo-Schneck
23

A RFC6648 recomenda que você assuma que o cabeçalho personalizado "possa se tornar padronizado, público, implantado normalmente ou utilizável em várias implementações". Portanto, recomenda não prefixá-lo com "X-" ou construções semelhantes.

No entanto, há uma exceção "quando é extremamente improvável que [seu cabeçalho] seja padronizado". Para esses cabeçalhos "de implementação específica e de uso privado", o RFC diz que um espaço para nome como um prefixo de fornecedor é justificado.

Edward Brey
fonte
6
"A RFC6648 recomenda que você assuma que seu cabeçalho personalizado" pode se tornar padronizado, público, comumente implantado ou utilizável em várias implementações. "Eu acho que isso fornece uma razão para usar o X-prefixo, porque é mais provável que algo sem prefixo possa se tornar padronizado.
Konrad
@ Konrad Se você assumir que o cabeçalho semelhante de outra pessoa (e não o seu cabeçalho) possa se tornar padronizado, você poderá evitar um conflito X-, mas essa é uma suposição diferente da utilizada pela RFC6648. A exceção da RFC é responsável por possíveis conflitos entre um cabeçalho padrão futuro e um cabeçalho de outro fornecedor cuja tecnologia possa se integrar à sua por meio de fusão de empresas etc. É por isso que a exceção exige um prefixo do fornecedor.
Edward Brey
17

Modificar, ou mais corretamente, adicionar cabeçalhos HTTP adicionais é uma ótima ferramenta de depuração de código, se nada mais.

Quando uma solicitação de URL retorna um redirecionamento ou uma imagem, não há "página" html para gravar temporariamente os resultados do código de depuração em - pelo menos não um que esteja visível em um navegador.

Uma abordagem é gravar os dados em um arquivo de log local e visualizá-lo mais tarde. Outra é adicionar temporariamente cabeçalhos HTTP, refletindo os dados e variáveis ​​sendo depurados.

Eu regularmente adiciono cabeçalhos HTTP extras como X-fubar-somevar: ou X-testing-someresult: para testar as coisas - e encontrei muitos bugs que, de outra forma, seriam muito difíceis de rastrear.

g1smd
fonte
2
Por que ele deveria usar esse "padrão"? Os cabeçalhos funcionam da mesma maneira. Mesmo com o prefixo "WHO_EVER_READS_THIS_IS_DUMB_" ...
O incrível
16

O registro do nome do campo do cabeçalho está definido no RFC3864 e não há nada de especial em "X-".

Até onde eu sei, não há diretrizes para cabeçalhos particulares; na dúvida, evite-os. Ou dê uma olhada no HTTP Extension Framework ( RFC 2774 ).

Seria interessante entender mais sobre o caso de uso; por que as informações não podem ser adicionadas ao corpo da mensagem?

Julian Reschke
fonte
13
A principal razão que eu estou considerando alguns cabeçalhos personalizados é para que eu possa fazer encaminhamento decisões sem ter que analisar o corpo ...
Rozwel