É válido substituir http: // por // em um <script src = "http: //…">?

458

Eu tenho o seguinte elemento:

<script type="text/javascript" src="https://cdn.example.com/js_file.js"></script>

Nesse caso, o site é HTTPS, mas também pode ser apenas HTTP. (O arquivo JS está em outro domínio.) Gostaria de saber se é válido fazer o seguinte por uma questão de conveniência:

<script type="text/javascript" src="//cdn.example.com/js_file.js"></script>

Gostaria de saber se é válido remover o http:ou https:?

Parece funcionar em todos os lugares que testei, mas existem casos em que não funciona?

Darryl Hein
fonte
2
O "parece funcionar em todos os lugares" pode ser generalizado para imagens, iframes, link-rels etc etc? Isso é interessante, se for o caso.
12345
Sim, ele deve funcionar em qualquer lugar que exija um URI: imagens, links etc. Pode ser raro ver isso em uso, mas é perfeitamente válido.
1540 Jeff Jeff
1
O que há com todos os caras que votaram instantaneamente? Não que a pergunta seja ruim ou algo assim, estou apenas curioso. Mas aposto que a reputação inicial de Chris tem influência.
Frederik Wordenskjold
13
@ Frederik: Porque é um truque fascinante e útil que a maioria das pessoas aparentemente não tem conhecimento.
SLaks
8
@Frederik: O que?
SLaks

Respostas:

387

Um URL relativo sem um esquema (http: ou https :) é válido, de acordo com a RFC 3986: "Uniform Resource Identifier (URI): sintaxe genérica", seção 4.2 . Se um cliente engasgar com isso, a culpa é do cliente, porque ele não está em conformidade com a sintaxe do URI especificada na RFC.

Seu exemplo é válido e deve funcionar. Eu mesmo usei esse método de URL relativo em sites com tráfego intenso e não recebi nenhuma reclamação. Além disso, testamos nossos sites no Firefox, Safari, IE6, IE7 e Opera. Todos esses navegadores entendem esse formato de URL.

Jeff
fonte
30
"Se um cliente engasga com isso, a culpa é do cliente, porque ele não está em conformidade com a sintaxe do URI especificada na RFC." - Acho que essa é uma pergunta interessante - mas se um cliente segue "as especificações" dificilmente é um bom padrão se é sábio fazer em um aplicativo da web.
22630 Matt Howell
6
Embora essa técnica pareça pouco conhecida, ela é suportada em todos os navegadores da web. Funciona muito bem.
Ned Batchelder
8
Gostaria de saber por que o google não usa isso para análise. Eles usam o método document.location.protocol.
Darryl Hein
5
@ Darryl Hein Eu acredito que o Google usa o método document.location.protocol porque também modifica o URL, não apenas o esquema. Eles vão para SSL.google-analytics.com se o documento estiver usando o esquema https.
Nick Meldrum
18
O Google não usa isso porque a pilha de rede do Windows XP não suporta SNI. Veja aqui: blogs.msdn.com/b/ieinternals/archive/2009/12/07/… . Portanto, permitir que o script do Google Analytics seja carregado por https no IE6 resultaria em um erro de certificado.
Eilistraee
152

É garantido que funcione em qualquer navegador convencional (não estou levando em consideração navegadores com menos de 0,05% de participação de mercado). Caramba, ele funciona no Internet Explorer 3.0.

O RFC 3986 define um URI como composto pelas seguintes partes:

     foo://example.com:8042/over/there?name=ferret#nose
     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment

Ao definir URIs relativos ( Seção 5.2 ), você pode omitir qualquer uma dessas seções, sempre começando pela esquerda. No pseudo-código, fica assim:

 result = ""

  if defined(scheme) then
     append scheme to result;
     append ":" to result;
  endif;

  if defined(authority) then
     append "//" to result;
     append authority to result;
  endif;

  append path to result;

  if defined(query) then
     append "?" to result;
     append query to result;
  endif;

  if defined(fragment) then
     append "#" to result;
     append fragment to result;
  endif;

  return result;

O URI que você está descrevendo é um URI relativo sem esquema.

Andrew Moore
fonte
1
Sim, acho que pensei que esquema e autoridade sempre eram mutuamente dependentes. Faz sentido que não seja, mas não é algo que encontrei até muito recentemente.
Chris
1
Não é garantido que funcione em qualquer navegador. É garantido que funcione apenas em navegadores que seguem o RFC.
2
@ Roger Pate: ainda não vi um navegador que siga o RFC para URI. Esse padrão em particular existe há tanto tempo ... Acabei de testá-lo no IE3.0 e entende perfeitamente bem. Se você cair em um navegador que não entende esses links, é provável que seja um navegador tão marginal que não importa.
Andrew Moore
1
@ Andrew: Talvez você seja diferente de mim, mas quando digo "garantia" no contexto da programação, eu realmente quero dizer "não há como isso possa eventualmente falhar", e não apenas ", ele só funciona em implementações populares que eu ' testei. " Eu não pretendia fazer um grande negócio com isso, mas parecia importante o suficiente para mencionar.
4
@ Roger: Sim, mas no contexto do desenvolvimento da Web, navegadores marginais (<0,01% de participação no mercado) não são levados em consideração. É como dizer que uma API está presente em todas as versões do Windows e então alguém vem dizer que ela pode não ser suportada no Wine ...
Andrew Moore
79

existem casos em que não funciona?

Se a página pai foi carregada file://, provavelmente não funcionará (ela tentará obter o file://cdn.example.com/js_file.jsque, é claro, você também poderia fornecer localmente).

Thilo
fonte
19
A deve saber para os caras testando html na máquina local!
Philip007
argh ... não admira que o meu script src="//..."não estivesse funcionando! Eu estava abrindo o arquivo html localmente!
wisbucky
Alguém sabe como contornar isso?
precisa saber é o seguinte
@ ogc-nick: Você pode executar um servidor web local. Atualmente, existem muitas opções, com configuração zero. Você quer que a de qualquer maneira, como muitas outras coisas (como XHR ou web trabalhadores também não fazer o trabalho para o arquivo: domínio)
Thilo
@Thilo Isso está funcionando temporariamente para mim, mas estou fazendo um aplicativo com o Electron do Github e isso fica um pouco mais complicado.
precisa
41

Muitas pessoas chamam isso de URL relativa ao protocolo.

Isso causa um download duplo de arquivos CSS no IE 7 e 8 .

SLaks
fonte
@AndrewMoore Como a "coisa" excluída indica o protocolo da web, chamá-lo de "relativo ao protocolo" faz mais sentido. Eu nunca ouvi falar de ftp ou http sendo chamado de "esquemas" ...
Cerin
25

Aqui duplico a resposta em Recursos ocultos do HTML :

Usando um caminho absoluto independente de protocolo:

<img src="//domain.com/img/logo.png"/>

Se o navegador estiver visualizando uma página em SSL por HTTPS, ele solicitará esse recurso com o protocolo https, caso contrário, ele solicitará com HTTP.

Isso evita a terrível mensagem de erro "Esta página contém itens seguros e não seguros" no IE, mantendo todas as solicitações de ativos dentro do mesmo protocolo.

Advertência: Quando usado em uma <link>importação ou @ para uma folha de estilo, o IE7 e o IE8 baixam o arquivo duas vezes . Todos os outros usos, no entanto, estão bem.

kennytm
fonte
17

É perfeitamente válido deixar de fora o protocolo. A especificação de URL tem sido muito clara sobre isso há anos, e ainda não encontrei um navegador que não o entenda. Não sei por que essa técnica não é mais conhecida; é a solução perfeita para o espinhoso problema de cruzar os limites HTTP / HTTPS. Mais aqui: transições HTTP-https e URLs relativos

Ned Batchelder
fonte
7

existem casos em que não funciona?

Só para colocar isso em ordem, se você estiver desenvolvendo em um servidor local, pode não funcionar. Você precisa especificar um esquema, caso contrário, o navegador pode assumir que src="//cdn.example.com/js_file.js"é src="file://cdn.example.com/js_file.js", o que será interrompido, pois você não está hospedando este recurso localmente.

O Microsoft Internet Explorer parece ser particularmente sensível a isso, consulte esta pergunta: Não é possível carregar o jQuery no Internet Explorer no localhost (WAMP)

Você provavelmente sempre tentaria encontrar uma solução que funcione em todos os seus ambientes com a menor quantidade de modificações necessárias.

A solução usada pelo HTML5Boilerplate é ter um fallback quando o recurso não for carregado corretamente, mas isso só funcionará se você incorporar uma verificação:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- If jQuery is not defined, something went wrong and we'll load the local file -->
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>

ATUALIZAÇÃO: o HTML5Boilerplate agora usa <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.jsapós decidir descontinuar URLs relativos ao protocolo, consulte [aqui] [3].

bg17aw
fonte
4

Seguindo a referência do gnud, a seção 5.2 do RFC 3986 diz:

Se o componente do esquema estiver definido, indicando que a referência começa com um nome de esquema, a referência é interpretada como um URI absoluto e pronto. Caso contrário, o esquema do URI de referência é herdado do componente do esquema do URI base .

Então //está correto :-)

Pablo Torrecilla
fonte
3

Sim, isso está documentado na RFC 3986 , seção 5.2:

(editar: Opa, minha referência RFC estava desatualizada).

gnud
fonte
3

É realmente correto, como outras respostas afirmaram. Você deve observar, no entanto, que alguns rastreadores da Web dispararão 404s para eles solicitando-os no seu servidor como se fosse um URL local. (Eles desconsideram a barra dupla e a tratam como uma barra única).

Você pode configurar uma regra em seu servidor da web para capturá-las e redirecioná-las.

Por exemplo, com o Nginx, você adicionaria algo como:

location ~* /(?<redirect_domain>((([a-z]|[0-9]|\-)+)\.)+([a-z])+)/(?<redirect_path>.*) {
  return 301 $scheme:/$redirect_domain/$redirect_path;
}

Observe, porém, que se você usar períodos em seus URIs, precisará aumentar a especificidade ou isso acabará redirecionando essas páginas para domínios inexistentes.

Além disso, esse é um regex bastante massivo para ser executado em cada consulta - na minha opinião, vale a pena punir navegadores não compatíveis com 404s por um (leve) desempenho atingido na maioria dos navegadores compatíveis.

jlovison
fonte
3

Estamos vendo erros 404 em nossos logs ao usar //somedomain.com como referências a arquivos JS.

As referências que causam os 404s aparecem assim: ref:

<script src="//somedomain.com/somescript.js" />

Solicitação 404:

http://mydomain.com//somedomain.com/somescript.js

Com isso aparecendo regularmente em nossos registros do servidor da Web, é seguro dizer que: Todos os navegadores e Bots NÃO respeitam a RFC 3986, seção 4.2. A aposta mais segura é incluir o protocolo sempre que possível.

Lemiarty
fonte
Sim, eu meio que mudei de assunto, mas não por causa dos 404s (nunca vi 404s ... se um bot não o respeitar, eu poderia me importar menos) - porque não carrego mais recursos de outras CDNs, para que eu não precise fazer isso (em vez disso, minizo o máximo possível em 1 ou 2 arquivos).
Darryl Hein
1
Por favor inclua o protocolo. As refs sem protocolo quebram no meu aplicativo Cordova.
Pgorsira
3

1. Resumo

Resposta para 2019: você ainda pode usar URLs relativos ao protocolo, mas essa técnica é um antipadrão .

Além disso:

  1. Você pode ter problemas no desenvolvimento.
  2. Algumas ferramentas de terceiros podem não suportá-las.

Migrar de URLs relativos ao protocolo para https://ele seria bom.


2. Relevância

Esta resposta é relevante para janeiro de 2019. No futuro, os dados desta resposta podem estar obsoletos.


3. Anti-padrão

3.1 Argumentação

Paul Irish - engenheiro front-end e defensor do desenvolvedor do Google Chrome - escreveu em 2014, dezembro :

Agora que o SSL é incentivado para todos e não tem problemas de desempenho , essa técnica agora é um antipadrão . Se o ativo necessário estiver disponível em SSL, use sempre ohttps:// .

Permitir que o snippet solicite por HTTP abre a porta para ataques como o recente ataque do lado do GitHub . É sempre seguro solicitar recursos HTTPS, mesmo que seu site esteja em HTTP; no entanto, o contrário não é verdadeiro .

3.2 Outros links

3.3 Exemplos


4. Processo de desenvolvimento

Por exemplo, tento usar o console limpo .

  • Arquivo de exemplo KiraCleanConsole__cdn_links_demo.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>clean-console without protocol demonstration</title>
    <!-- Really dead link -->
    <script src="https://unpkg.com/bowser@latest/bowser.min.js"></script>
    <!-- Package exists; link without “https:” -->
    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
    <!-- Package exists: link with “https:” -->
    <script src="https://cdn.jsdelivr.net/npm/gemini-scrollbar/index.js"></script>
</head>
<body>
    Kira Goddess!
</body>
</html>
  • resultado:
D:\SashaDebugging>clean-console -i KiraCleanConsole__cdn_links_demo.html
checking KiraCleanConsole__cdn_links_demo.html
phantomjs: opening page KiraCleanConsole__cdn_links_demo.html

phantomjs: Unable to load resource (#3URL:file://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js)


phantomjs:   phantomjs://code/runner.js:30 in onResourceError
Error code: 203. Description: Error opening //cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js: The network path was not found.

  phantomjs://code/runner.js:31 in onResourceError

phantomjs: Unable to load resource (#5URL:https://unpkg.com/[email protected]/bowser.min.js)


phantomjs:   phantomjs://code/runner.js:30 in onResourceError
Error code: 203. Description: Error downloading https://unpkg.com/[email protected]/bowser.min.js - server replied: Not Found

  phantomjs://code/runner.js:31 in onResourceError

phantomjs: Checking errors after sleeping for 1000ms
2 error(s) on KiraCleanConsole__cdn_links_demo.html

phantomjs process exited with code 2

Ligação //cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js é válido, mas estou recebendo um erro.

Preste atenção file://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.jse leia as respostas Thilo e bg17aw sobrefile:// .

Eu não sabia sobre esse comportamento e não conseguia entender por que tenho problemas como esse para pageres .


5. Ferramentas de terceiros

Eu uso o pacote de texto sublime de URLs clicáveis . Use-o, eu posso simplesmente abrir links do meu editor de texto no navegador.

Exemplos de links CSS

Os dois links no exemplo são válidos. Mas o primeiro link que posso abrir com sucesso no navegador usa URLs clicáveis, segundo link - não. Isso pode não ser muito conveniente.


6. Conclusão

Sim:

  1. Se você tiver problemas como no Developing processitem, poderá definir seu fluxo de trabalho de desenvolvimento.
  2. Caso contrário, você tem problemas, como no Third-party toolsitem, você pode contribuir com ferramentas.

Mas você não precisa desses problemas adicionais. Leia as informações por links no Anti-patternitem: URLs relativas ao protocolo estão obsoletas.

Саша Черных
fonte
2

O padrão que vejo no html5-boilerplate é:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>

Ele roda sem problemas em diferentes esquemas como http, https, file.

neurite
fonte
Isso não é mais verdade, ver stackoverflow.com/a/37609402/2237601 ou aqui , eles agora usam https://para tudo
bg17aw
@ bg17aw O problema de usar https://todos os lugares é que você deve verificar todos os seus links externos para ver se eles realmente o suportam e alterá-los para http://se não o fizerem (caso contrário, eles não funcionarão). Isso pode ser problemático com um grande número de links.
tomasz86
@ tomasz86 você está perdendo o ponto, eu estava me referindo apenas ao caso particular de vincular ao conteúdo das CDNs. https: // é obrigatório para isso hoje em dia. A resposta também fala sobre um caso específico (html5-boilerplate). Não há "verificação de http" como você diz, pois as CDNs sempre usam https agora.
bg17aw
@ bg17aw Isso é verdade, mas a questão geral aqui não é apenas sobre CDNs. Ao ler apenas esta resposta / comentário, é fácil pensar que https://deve (ou pode) ser usado em todos os links que não estão corretos.
tomasz86
@ tomasz86 A beleza de ter várias respostas é que, enquanto nenhuma delas é perfeita (se uma resposta for perfeita, as outras precisariam ser excluídas), ler algumas delas nos dá uma visão mais ampla. Nesse caso, a resposta diz "o padrão no html5boilerplate é ..." e meu comentário atualiza essa resposta mencionando "que não é mais o padrão no html5-boilerplate". É isso aí. Uma adição necessária a esta resposta específica. Observe também que a pergunta original é realmente sobre CDNs!
precisa saber é o seguinte
1

Como seu exemplo está vinculando a um domínio externo, se você estiver usando HTTPS, verifique se o domínio externo também está configurado para SSL. Caso contrário, seus usuários poderão ver erros SSL e / ou 404 (por exemplo, versões mais antigas do Plesk armazenam HTTP e HTTPS em pastas separadas). Para CDNs, não deve ser um problema, mas para qualquer outro site.

Em uma nota lateral, testado enquanto atualizamos um site antigo e também funciona na parte url = de um META REFRESH.

user2246924
fonte