¿Es válido reemplazar http: // con // en un <script src = "http: // ...">?

458

Tengo el siguiente elemento:

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

En este caso, el sitio es HTTPS, pero también puede ser solo HTTP. (El archivo JS está en otro dominio). Me pregunto si es válido hacer lo siguiente por conveniencia:

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

Me pregunto si es válido eliminar el http:o https:.

Parece que funciona en todos los lugares que he probado, pero ¿hay algún caso en el que no funcione?

Darryl Hein
fuente
2
¿Puede el "parece funcionar en todas partes" generalizarse a imágenes, marcos flotantes, enlaces, etc., etc.? Esto es algo interesante, si es así.
12345
Sí, debería funcionar en cualquier lugar que requiera un URI: imágenes, enlaces, etc. Puede ser raro ver esto en uso, pero es perfectamente válido.
Jeff
1
¿Qué pasa con todos esos muchachos de votación instantánea? No es que la pregunta sea mala ni nada, solo tengo curiosidad. Pero apuesto a que la reputación inicial de Chris tiene influencia.
Frederik Wordenskjold
13
@Frederik: Porque es un truco fascinante y útil que la mayoría de las personas aparentemente desconocen.
SLaks
8
@Frederik: ¿Qué?
SLaks

Respuestas:

387

Una URL relativa sin un esquema (http: o https :) es válida, según RFC 3986: "Identificador uniforme de recursos (URI): sintaxis genérica", sección 4.2 . Si un cliente se ahoga, entonces es culpa del cliente porque no cumple con la sintaxis de URI especificada en el RFC.

Su ejemplo es válido y debería funcionar. Yo mismo he usado ese método de URL relativo en sitios con mucho tráfico y no he tenido ninguna queja. Además, probamos nuestros sitios en Firefox, Safari, IE6, IE7 y Opera. Todos estos navegadores entienden ese formato de URL.

Jeff
fuente
30
"Si un cliente se atraganta, es culpa del cliente porque no cumple con la sintaxis de URI especificada en el RFC". - Creo que esta es una pregunta interesante, pero si un cliente sigue "la especificación" no es un buen estándar para saber si es aconsejable hacerlo en una aplicación web.
Matt Howell
66
Aunque esta técnica parece ser poco conocida, es compatible con todos los navegadores web. Funciona muy bien
Ned Batchelder
8
Me pregunto por qué Google no usa esto para análisis. Usan el método document.location.protocol.
Darryl Hein
55
@Darryl Hein Creo que Google usa el método document.location.protocol porque también modifica la url, no solo el esquema. Van a SSL.google-analytics.com si el documento está usando el esquema https.
Nick Meldrum
18
google no usa esto porque la pila de red de Windows XP no es compatible con SNI. Ver aquí: blogs.msdn.com/b/ieinternals/archive/2009/12/07/… . Por lo tanto, permitir que el script de Google Analytics se cargue a través de https en IE6 daría lugar a un error de certificado.
Eilistraee
152

Se garantiza que funcione en cualquier navegador convencional (no estoy teniendo en cuenta los navegadores con menos del 0.05% de cuota de mercado). Diablos, funciona en Internet Explorer 3.0.

RFC 3986 define un URI como compuesto de las siguientes partes:

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

Al definir los URI relativos ( Sección 5.2 ), puede omitir cualquiera de esas secciones, siempre comenzando desde la izquierda. En pseudocódigo, se ve así:

 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;

El URI que está describiendo es un URI relativo sin esquema.

Andrew Moore
fuente
1
Sí, supongo que pensé que el esquema y la autoridad siempre eran mutuamente dependientes. Tiene sentido que no lo sea, pero no es algo que haya encontrado hasta hace muy poco.
Chris
1
No se garantiza que funcione en ningún navegador. Se garantiza que funciona solo en los navegadores que siguen el RFC.
2
@Roger Pate: aún no he visto un navegador que no siga el RFC para URI. Ese estándar en particular ha existido durante tanto tiempo ... Acabo de probarlo en IE3.0 y lo entiende perfectamente. Si cae en un navegador que no comprende esos enlaces, es probable que sea un navegador tan marginal que no importará.
Andrew Moore
1
@ Andrew: Tal vez usted difiere de mí, pero cuando digo "garantía" en el contexto de la programación, realmente quiero decir "no hay forma de que esto pueda fallar", no solo ", solo funciona en implementaciones populares que yo ' he probado ". No quise hacer un gran problema, pero parecía lo suficientemente importante como para mencionarlo.
44
@Roger: Sí, pero en el contexto del desarrollo web, los navegadores marginales (<0.01% de cuota de mercado) no se tienen en cuenta. Es como decir que una API está presente en todas las versiones de Windows y luego alguien viene a decir que podría no ser compatible con Wine ...
Andrew Moore
79

¿Hay algún caso en el que no funciona?

Si se cargó la página principal file://, entonces probablemente no funcione (intentará obtenerla file://cdn.example.com/js_file.js, que por supuesto también podría proporcionar localmente).

Thilo
fuente
19
¡Una visita obligada para los chicos que prueban HTML en la máquina local!
Philip007
argh ... no es de extrañar que mi script src="//..."no estaba funcionando! ¡Estaba abriendo el archivo html localmente!
wisbucky
Alguien sabe una forma de evitar esto?
km6zla
@ ogc-nick: puede ejecutar un servidor web local. Muchas opciones en estos días, con configuración cero. Lo desea de todos modos, ya que muchas otras cosas (como XHR o los trabajadores web tampoco funcionan para el archivo: dominio)
Thilo
@Thilo Eso ha estado funcionando temporalmente para mí, pero estoy haciendo una aplicación con Github's Electron y eso se vuelve un poco más complicado.
km6zla
41

Mucha gente llama a esto una URL relativa al protocolo.

Causa una doble descarga de archivos CSS en IE 7 y 8 .

SLaks
fuente
@AndrewMoore Como la "cosa" que se excluye indica el protocolo web, llamarlo "protocolo relativo" tiene más sentido. Nunca he oído hablar de ftp o http llamado "esquemas" ...
Cerin
25

Aquí duplico la respuesta en las características ocultas de HTML :

Usando una ruta absoluta independiente del protocolo:

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

Si el navegador está viendo una página en SSL a través de HTTPS, solicitará ese activo con el protocolo https; de lo contrario, lo solicitará con HTTP.

Esto evita el horrible mensaje de error "Esta página contiene elementos seguros y no seguros" en IE, manteniendo todas sus solicitudes de activos dentro del mismo protocolo.

Advertencia: cuando se usa en una <link>o @import para una hoja de estilo, IE7 e IE8 descargan el archivo dos veces . Todos los demás usos, sin embargo, están bien.

kennytm
fuente
17

Es perfectamente válido dejar de lado el protocolo. La especificación de URL ha sido muy clara sobre esto durante años, y todavía tengo que encontrar un navegador que no lo entienda. No sé por qué esta técnica no se conoce mejor; Es la solución perfecta para el espinoso problema de cruzar los límites HTTP / HTTPS. Más aquí: transiciones Http-https y URL relativas

Ned Batchelder
fuente
7

¿Hay algún caso en el que no funciona?

Solo para agregar esto a la mezcla, si está desarrollando en un servidor local, podría no funcionar. Debe especificar un esquema, de lo contrario, el navegador puede suponer que src="//cdn.example.com/js_file.js"es así src="file://cdn.example.com/js_file.js", lo que se romperá ya que no está alojando este recurso localmente.

Microsoft Internet Explorer parece ser particularmente sensible a esto, vea esta pregunta: No se puede cargar jQuery en Internet Explorer en localhost (WAMP)

Probablemente siempre intente encontrar una solución que funcione en todos sus entornos con la menor cantidad de modificaciones necesarias.

La solución utilizada por HTML5Boilerplate es tener un respaldo cuando el recurso no se carga correctamente, pero eso solo funciona si incorpora una verificación:

<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>

ACTUALIZACIÓN: HTML5Boilerplate ahora usa <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.jsdespués de decidir desaprobar las URL relativas del protocolo, consulte [aquí] [3].

bg17aw
fuente
4

Siguiendo la referencia del gnud, la sección 5.2 del RFC 3986 dice:

Si el componente del esquema está definido, lo que indica que la referencia comienza con un nombre de esquema, entonces la referencia se interpreta como un URI absoluto y hemos terminado. De lo contrario, el esquema del URI de referencia se hereda del componente del esquema del URI base .

Entonces //es correcto :-)

Pablo Torrecilla
fuente
3

Sí, esto está documentado en RFC 3986 , sección 5.2:

(editar: Vaya, mi referencia RFC estaba desactualizada).

GNUD
fuente
3

De hecho, es correcto, como han dicho otras respuestas. Sin embargo, debe tener en cuenta que algunos rastreadores web activarán 404 para estos solicitándolos en su servidor como si fuera una URL local. (No tienen en cuenta el doble corte y lo tratan como un solo corte).

Es posible que desee configurar una regla en su servidor web para capturarlos y redirigirlos.

Por ejemplo, con Nginx, agregaría algo como:

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

Sin embargo, tenga en cuenta que si usa períodos en sus URI, deberá aumentar la especificidad o terminará redirigiendo esas páginas a dominios inexistentes.

Además, esta es una expresión regular bastante masiva para cada consulta; en mi opinión, vale la pena castigar a los navegadores no conformes con 404 por encima de un (leve) éxito de rendimiento en la mayoría de los navegadores conformes.

jlovison
fuente
3

Estamos viendo errores 404 en nuestros registros cuando usamos //somedomain.com como referencias a archivos JS.

Las referencias que causan los 404 salen así: ref:

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

Solicitud 404:

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

Con esto apareciendo regularmente en los registros de nuestro servidor web, es seguro decir que: Todos los navegadores y Bots NO cumplen con RFC 3986 sección 4.2. La apuesta más segura es incluir el protocolo siempre que sea posible.

Lemiartia
fuente
Sí, me he alejado un poco de él, pero no debido a los 404 (nunca he visto ningún 404 ... si un bot no lo honra, me importaría menos), porque ya no cargo recursos de otros CDN, así que no necesito hacer esto (en cambio, minimizo lo más posible en 1 o 2 archivos).
Darryl Hein
1
Por favor incluya el protocolo. Las referencias sin protocolo se rompen en mi aplicación Cordova.
pgorsira
3

1. Resumen

Respuesta para 2019: aún puede usar URL relativas al protocolo, pero esta técnica es un antipatrón .

También:

  1. Puede tener problemas para desarrollarse.
  2. Algunas herramientas de terceros pueden no ser compatibles.

https://Sería bueno migrar desde URL relativas al protocolo a él.


2. Relevancia

Esta respuesta es relevante para enero de 2019. En el futuro, los datos de esta respuesta pueden quedar obsoletos.


3. Anti-patrón

3.1. Argumentación

Paul Irish, ingeniero front-end y defensor del desarrollador para Google Chrome , escribe en 2014, diciembre :

Ahora que se recomienda SSL para todos y no tiene problemas de rendimiento , esta técnica ahora es un antipatrón . Si el activo que necesita está disponible en SSL, use siempre el https://activo.

Permitir que el fragmento solicite a través de HTTP abre la puerta a ataques como el reciente ataque GitHub Man-on-the-side . Siempre es seguro solicitar activos HTTPS incluso si su sitio está en HTTP, sin embargo, lo contrario no es cierto .

3.2. Otros enlaces

3.3. Ejemplos


4. Proceso de desarrollo

Por ejemplo, trato de usar la consola limpia .

  • Archivo de ejemplo 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>
  • salida:
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

El enlace //cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.jses válido, pero recibo un error.

Presta atención file://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.jsy lee las respuestas de Thilo y bg17awfile:// .

No sabía sobre este comportamiento y no podía entender por qué tengo problemas como este para los pageres .


5. Herramientas de terceros

Utilizo el paquete de texto sublime de URLs clicables. Úselo, simplemente puedo abrir enlaces desde mi editor de texto en el navegador.

Ejemplos de enlaces CSS

Ambos enlaces, por ejemplo, son válidos. Pero el primer enlace que puedo abrir con éxito en el navegador usa URL clicables, segundo enlace - no. Esto puede no ser muy conveniente.


6. Conclusión

Si:

  1. Si tiene problemas como en el Developing processelemento, puede configurar su flujo de trabajo de desarrollo.
  2. De lo contrario, tiene problemas como en el Third-party toolsartículo, puede contribuir con herramientas.

Pero no necesita estos problemas adicionales. Lea la información por enlaces en el Anti-patternelemento: las URL relativas al protocolo están obsoletas.

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

El patrón que veo en html5-boilerplate es:

<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>

Se ejecuta sin problemas en diferentes esquemas como http, https, file.

neurita
fuente
Esto ya no es cierto, consulte stackoverflow.com/a/37609402/2237601 o aquí , ahora lo usan https://para todo
bg17aw
@ bg17aw El problema con el uso en https://todas partes es que luego debe seguir revisando todos sus enlaces externos para ver si realmente lo admiten, y cambiarlos a http://si no lo hacen (de lo contrario, no funcionarán). Esto puede ser problemático con una gran cantidad de enlaces.
tomasz86
@ tomasz86 te estás perdiendo el punto, solo me refería al caso particular de vincular al contenido de CDN. https: // es obligatorio para eso hoy en día. La respuesta también habla de un caso particular (html5-boilerplate). No hay "comprobación de http" como usted dice, ya que los CDN siempre usan https ahora.
bg17aw
@ bg17aw Eso es cierto, pero la pregunta general aquí no es solo acerca de los CDN. Al leer solo esta respuesta / comentario, es fácil pensar que https://debería (o puede) usarse en todos los enlaces que no es correcto.
tomasz86
@ tomasz86 La belleza de tener múltiples respuestas es que, si bien ninguna de ellas es perfecta (si una respuesta fuera perfecta, las otras tendrían que eliminarse), leer algunas de ellas nos da una visión más amplia. En este caso, la respuesta dice "el patrón en html5boilerplate es ..." y mi comentario actualiza esta respuesta mencionando "ese ya no es el patrón en html5-boilerplate". Eso es. Una adición necesaria a esta respuesta particular. ¡También tenga en cuenta que la pregunta original es sobre CDN!
bg17aw
1

Como su ejemplo se vincula a un dominio externo, si está utilizando HTTPS, entonces debe verificar que el dominio externo también esté configurado para SSL. De lo contrario, sus usuarios pueden ver errores SSL y / o errores 404 (por ejemplo, las versiones anteriores de Plesk almacenan HTTP y HTTPS en carpetas separadas). Para las CDN, no debería ser un problema, pero podría serlo para cualquier otro sitio web.

En una nota al margen, probado mientras se actualiza un sitio web antiguo y también funciona en la url = parte de una actualización META.

usuario2246924
fuente