El navegador no puede acceder / encontrar recursos relativos como CSS, imágenes y enlaces al llamar a un Servlet que reenvía a un JSP

82

Tengo problemas para cargar CSS e imágenes y crear enlaces a otras páginas cuando tengo un servlet que reenvía a un JSP. Específicamente, cuando configuro mi <welcome-file>en index.jsp, el CSS se carga y mis imágenes se muestran. Sin embargo, si configuro mi control <welcome-file>a HomeServletqué reenvíos index.jsp, el CSS no se aplica y mis imágenes no se muestran.

Mi archivo CSS está en formato web/styles/default.css.
Mis imágenes están en web/images/.

Me estoy vinculando a mi CSS así:

<link href="styles/default.css" rel="stylesheet" type="text/css" />

Estoy mostrando mis imágenes de la siguiente manera:

<img src="images/image1.png" alt="Image1" />

¿Cómo se produce este problema y cómo puedo solucionarlo?


Actualización 1 : agregué la estructura de la aplicación, así como otra información que podría ayudar.

texto alternativo

El header.jsparchivo es el archivo que contiene la etiqueta de enlace para CSS. El HomeServletestá configurado como mi welcome-fileen web.xml:

<welcome-file-list>
    <welcome-file>HomeServlet</welcome-file>
</welcome-file-list>

El servlet se declara y se asigna de la siguiente manera en web.xml:

<servlet>
    <servlet-name>HomeServlet</servlet-name>
    <servlet-class>com.brianblog.frontend.HomeServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>HomeServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Actualización 2 : finalmente encontré el problema: mi servlet se asignó incorrectamente. Aparentemente, al configurar un Servlet como suyo, <welcome-file>no puede tener un patrón de URL /, lo cual me parece un poco extraño, porque ¿no representaría el directorio raíz del sitio?

El nuevo mapeo es el siguiente:

<servlet-mapping>
    <servlet-name>HomeServlet</servlet-name>
    <url-pattern>/HomeServlet</url-pattern>
</servlet-mapping>
Brian DiCasa
fuente
Gracias por la actualización 2, he estado golpeando mi cabeza contra la pared durante un par de horas tratando de averiguar por qué mi css no se estaba cargando. (tenía / como la anotación).
kiwicomb123

Respuestas:

100

Todas las URL relativas en la página HTML generada por el archivo JSP son relativas a la URL de solicitud actual (la URL como se ve en la barra de direcciones del navegador) y no a la ubicación del archivo JSP en el lado del servidor como parece esperar. Es decir, es el navegador web quien tiene que descargar esos recursos individualmente por URL, no el servidor web quien tiene que incluirlos desde el disco de alguna manera.

Aparte de cambiar las URL relativas para que sean relativas a la URL del servlet en lugar de la ubicación del archivo JSP, otra forma de solucionar este problema es hacerlas relativas a la raíz del dominio (es decir, comenzar con a /). De esta manera, no necesita preocuparse por cambiar las rutas relativas una vez más cuando cambie la URL del servlet.

<head>
    <link rel="stylesheet" href="/context/css/default.css" />
    <script src="/context/js/default.js"></script>
</head>
<body>
    <img src="/context/img/logo.png" />
    <a href="/context/page.jsp">link</a>
    <form action="/context/servlet"><input type="submit" /></form>
</body>

Sin embargo, probablemente le gustaría no codificar la ruta de contexto. Muy razonable. Puede obtener la ruta de contexto en EL mediante ${pageContext.request.contextPath}.

<head>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/css/default.css" />
    <script src="${pageContext.request.contextPath}/js/default.js"></script>
</head>
<body>
    <img src="${pageContext.request.contextPath}/img/logo.png" />
    <a href="${pageContext.request.contextPath}/page.jsp">link</a>
    <form action="${pageContext.request.contextPath}/servlet"><input type="submit" /></form>
</body>

(que se puede acortar <c:set var="root" value="${pageContext.request.contextPath}" />y utilizar fácilmente como en ${root}cualquier otro lugar)

O, si no le teme al XML ilegible y al resaltado de sintaxis XML roto, use JSTL <c:url> :

<head>
    <link rel="stylesheet" href="<c:url value="/css/default.css" />" />
    <script src="<c:url value="/js/default.js" />"></script>
</head>
<body>
    <img src="<c:url value="/img/logo.png" />" />
    <a href="<c:url value="/page.jsp" />">link</a>
    <form action="<c:url value="/servlet" />"><input type="submit" /></form>
</body>

De cualquier manera, esto es a su vez bastante engorroso si tiene muchas URL relativas. Para eso puedes usar la <base>etiqueta. Todas las URL relativas se convertirán instantáneamente en relativas a él. Sin embargo, tiene que comenzar con el esquema ( http://, https://, etc.). No hay una forma clara de obtener la ruta del contexto base en EL simple, por lo que necesitamos un poco de ayuda de JSTL aquí.

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="req" value="${pageContext.request}" />
<c:set var="uri" value="${req.requestURI}" />
<c:set var="url">${req.requestURL}</c:set>
...
<head>
    <base href="${fn:substring(url, 0, fn:length(url) - fn:length(uri))}${req.contextPath}/" />
    <link rel="stylesheet" href="css/default.css" />
    <script src="js/default.js"></script>
</head>
<body>
    <img src="img/logo.png" />
    <a href="page.jsp">link</a>
    <form action="servlet"><input type="submit" /></form>
</body>

Esto tiene a su vez (nuevamente) algunas advertencias. ¡Los anclajes (las #identifierURL) también se volverán relativos a la ruta base! En su lugar, le gustaría hacerlo relativo a la URL de solicitud (URI). Entonces, cambia como

<a href="#identifier">jump</a>

a

<a href="${uri}#identifier">jump</a>

Cada forma tiene sus pros y sus contras. Depende de usted cuál elegir. Al menos, ahora debe comprender cómo se causa este problema y cómo resolverlo :)

Ver también:

BalusC
fuente
Realmente esperaba que esto funcionara como tiene sentido, pero el navegador aún no puede localizar los archivos. Agregué más información a mi pregunta (estructura de la aplicación y otra información general). ¡Gracias por la ayuda!
Brian DiCasa
3
Ha asignado el servlet en /(olor, olor;)). Por lo tanto, también intercepta archivos CSS (de hecho, todas las solicitudes HTTP). ¿Los está manejando correctamente? Es decir, ¿puede acceder al archivo CSS directamente en el navegador web mediante localhost: 8080 / context / styles / default.css ?
BalusC
No cuando se asignó a "/". Sin embargo, puedo cuando está mapeado como "/ HomeServlet".
Brian DiCasa
No estoy seguro de por qué lo asignó inicialmente /*, pero si está tratando de crear una especie de controlador frontal, le sugiero que lea esta respuesta y tal vez también esta respuesta .
BalusC
@BalusC - En su primer párrafo, donde dijo "Es el navegador web quien tiene que descargar esos recursos individualmente por URL, no el servidor web quien tiene que incluirlos del disco de alguna manera". ¿Podemos comprobar de forma práctica que es responsabilidad del navegador buscar los recursos y no del servidor web? Si puedes señalarme algún ejemplo práctico o tutorial, ¡será genial!
Abhishek Aggarwal
2

Debe analizar la salida HTML real, para la pista.

Al dar la ruta de esta manera significa "desde la ubicación actual", por otro lado, si comienza con, /eso significaría "desde el contexto".

Adeel Ansari
fuente
No estoy seguro de lo que quieres decir. Si cambio el enlace css a esto:
Brian DiCasa
Quiero decir que puede ver la fuente HTML desde su navegador, para saber si la ruta es correcta o no. Si no es así, ¿qué debe hacer para corregirlo?
Adeel Ansari
He estado viendo la fuente y lo que aparece en mis etiquetas de enlace es lo que publiqué en mi pregunta. Supongo que no estoy seguro de por qué si me vinculo directamente a mi jsp, que los archivos se pueden encontrar y, si hago un reenvío, no se pueden encontrar. ¿Dónde puedo almacenar mis imágenes para que se puedan encontrar desde cualquier ubicación en la aplicación web?
Brian DiCasa
Bien, es porque tu index.jspestá en la misma ubicación / nivel que tus directorios stylesy images. Por lo tanto, cuando lo usa directamente index.jspcomo archivo de bienvenida, todo parece como un encanto. Por otro lado, cuando reenvía el mismo recurso a través del servlet, el asunto ya no es el mismo. [continuará ...]
Adeel Ansari
@Brian D .: ... Para dirigir una solicitud a un servlet en particular, no consideramos la ruta, usamos el mapeo de servlets. Ahora, debemos entender el context pathaquí. Como ha visto en los documentos, /tiene un significado específico cuando se usa en la ruta que queremos reenviar la solicitud o redirigir la solicitud. Sin la barra, se tomará de la ubicación actual, no de la ruta de contexto. Espero que me entiendas ahora.
Adeel Ansari
0

Su página de bienvenida está configurada como That Servlet. Por lo tanto, todas las rutas de acceso de imágenes y css deben proporcionarse en relación con ese servlet DIR. que es una mala idea! ¿Por qué necesita el servlet como página de inicio? establecer .jsp como página de índice y redirigir a cualquier página desde allí?

¿Está tratando de completar algún campo de db? ¿Es por eso que está usando servlet?

GoodSp33d
fuente
4
Usar un servlet como controlador frontal (MVC) ciertamente no es una mala idea.
BalusC
0

Si está utilizando Spring MVC, debe declarar el servlet de acción predeterminado para los contenidos estáticos. Agregue las siguientes entradas en spring-action-servlet.xml. Funcionó para mí.

NOTA: mantenga todos los contenidos estáticos fuera de WEB-INF.

<!-- Enable annotation-based controllers using @Controller annotations -->
<bean id="annotationUrlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="order" value="0" />
</bean>

<bean id="controllerClassNameHandlerMapping" class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
    <property name="order" value="1" />
</bean>

<bean id="annotationMethodHandlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
AjayP
fuente
0

En cuanto a su actualización, estaba confundido por el razonamiento detrás. Cavé un poco más y encontré esta joya:

  • yoursite.com se convierte en yoursite.com/
  • yoursite.com/ es un directorio, por lo que se escanea la lista de archivos de bienvenida
  • yoursite.com/CMS es el primer archivo de bienvenida ("CMS" en la lista de archivos de bienvenida), y hay una asignación de / CMS al servlet MyCMS, por lo que se accede a ese servlet.

Fuente: http://wiki.metawerx.net/wiki/HowToUseAServletAsYourMainWebPage

Entonces, el mapeo tiene sentido.

¡Y ahora se puede usar libremente $ {pageContext.request.contextPath} / path / as src / href para enlaces relativos!

Justin Cuaresma
fuente
0

respuesta corta: agregue la siguiente línea en el jsp que definirá la base
base href = "/ {raíz de su aplicación} /"

Ankit Pandoh
fuente
0

El siguiente código funcionó para mí.

en lugar de utilizar <% @ include file = "styles / default.css"%>

Chamika Ravinda
fuente
0

Puedes probar este también. Porque esto funcionó para mí y es simple.

<style>
    <%@ include file="/css/style.css" %>
</style>
Dulya Perera
fuente