¿Tu proyecto Laravel tiene HTTPS y no cargan las imágenes, estilos, o scripts?
Tiempo de lectura: 2.84 minutos
Cuando añadimos un protocolo seguro a nuestro dominio es común que los assets de nuestra aplicación dejen de cargar adecuadamente. Aprende cómo solucionar este problema ya mismo!
Introducción
¿Has configurado tu dominio para que funcione con HTTPS y ahora sucede que no cargan los recursos de tu proyecto Laravel?
Este es un problema muy común, pero no te preocupes porque ahora mismo vamos a solucionarlo.
El problema a solucionar
¿Te sucede lo siguiente?
- No cargan las imágenes
- No cargan los archivos Javascript
- No cargan las hojas de estilo (CSS)
El problema radica en que una página segura (con protocolo HTTPS) no puede ni debe cargar recursos que no son seguros (que se sirven a través del protocolo HTTP).
Tal como lo indica la siguiente imagen:
Si usas los helpers url
y asset
para generar enlaces absolutos a tus recursos y otras páginas de tu aplicación, y éstos enlaces se crean usando HTTP en vez de HTTPS, ese es justamente el problema.
¿Tienes algunos recursos que sí son cargados correctamente? Lo más probable es que estés usando rutas relativas para acceder a ellos.
Pero no es adecuado que cambies todos los enlaces absolutos de tu aplicación por unos relativos, porque siempre existirá el riesgo de que se te escapen algunos.
Lo que veremos ahora es una solución general para que los enlaces absolutos se creen haciendo uso de HTTPS.
Una solución en 2 pasos
Lo que haremos será:
- Definir nuestra propia clase
Request
. - Indicar a Laravel que use nuestra clase
Request
en vez de la que viene por defecto.
Paso 1: Definir nuestra propia clase Request
Vamos a crear una clase Request que extienda de la clase Request original, y vamos a sobreescribir el método isSecure
por uno más adecuado.
Por lo tanto, copia el siguiente código y úsalo para crear una clase Request.
<?php namespace App\Custom\Http;
use \Illuminate\Http\Request as Base;
class Request extends Base {
public function isSecure() {
$isSecure = parent::isSecure();
if ($isSecure) {
return true;
}
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
return true;
} else if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
return true;
}
return false;
}
}
En este caso yo he creado 2 carpetas nuevas, una dentro de otra y he ubicado allí la clase Request:
Para tu proyecto puedes situar esta clase donde creas conveniente, pero de ser así recuerda actualizar el namespace
que aparece en la primera línea.
Paso 2: Indicar a Laravel qué clase Request usar
Para esto ve a public/index.php
y reemplaza este fragmento de código:
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
Por este otro:
$response = $kernel->handle(
$request = App\Custom\Http\Request::capture()
);
Y eso es todo :)
Conclusión
Luego de aplicar los cambios, si usas asset('ruta/a/tu/recurso.css')
el resultado que se va a imprimir sobre tu página es https://tudominio.com/ruta/a/tu/recurso.css
.
Antes del cambio, el resultado era de esta forma: http://tudominio.com/ruta/a/tu/recurso.css
.
Pero tus enlaces relativos no se veían afectados porque /ruta/a/tu/recurso.css
es equivalente a https://tudominio.com/ruta/a/tu/recurso.css
cuando estás cargando el recurso desde https://tudominio.com/
.
Luego del cambio, la página volverá a ser la misma de siempre:
Bonus: Redirección de HTTP y www a HTTPS y non-www
No es adecuado si tu página es accesible con y sin www al inicio, ya que los buscadores (como Google) pueden calificar ello como contenido duplicado. Lo más adecuado es que decidas si quieres usar www o no, y redirigir de un caso al otro.
Por ejemplo, si prefieres usar https://tudominio.com
, debes hacer la redirección correspondiente para cuando tus visitas lleguen a:
- http://tudominio.com
- http://www.tudominio.com
- https://www.tudominio.com
Hay muchas formas de hacerlo. Por ejemplo, puedes añadir la condición en la declaración de VirtualHosts, usar servicios como CloudFlare, o bien agregar estas líneas en tu .htaccess
(ubicado al interior de la carpeta public
):
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
RewriteCond %{HTTP_HOST} ^www.tudominio.com$ [NC]
RewriteRule ^(.*)$ https://tudominio.com/ [R=301,L]
Puedes agregar estas líneas luego de RewriteEngine On
.
- La primera condición y regla activan HTTPS cuando es necesario.
- Y la seguna condición elimina www para el dominio.
En realidad hay forma de condicionar con un OR
y aplicar una sola regla de redirección:
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://tudominio.com%{REQUEST_URI} [L,NE,R=301]
El detalle está en que esto último siempre hace la redirección, incluso si estás trabajando desde un host local.
A fin de usar un mismo .htaccess
es conveniente la primera alternativa (donde aplicamos siempre el HTTPS pero la redirección sólo de manera específica para el dominio de producción).