调用转发到 JSP 的 Servlet 时,浏览器无法访问/查找相关资源,如 CSS、图像和链接

2022-01-30 00:00:00 image css jsp servlets

当我将 servlet 转发到 JSP 时,我无法加载 CSS 和图像以及创建指向其他页面的链接.具体来说,当我将 <welcome-file> 设置为 index.jsp 时,正在加载 CSS 并显示我的图像.但是,如果我将 <welcome-file> 设置为 HomeServlet 将控制权转发给 index.jsp,则不会应用 CSS 并且我的图像没有显示.

我的 CSS 文件位于 web/styles/default.css.
我的图片在 web/images/ 中.

我像这样链接到我的 CSS:

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

我的图像显示如下:

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

这个问题是怎么引起的,我该如何解决?

<小时>

更新 1:我添加了应用程序的结构,以及一些其他可能有帮助的信息.

header.jsp 文件是包含 CSS 链接标记的文件.HomeServletweb.xml 中设置为我的 welcome-file:

<welcome-file-list><welcome-file>HomeServlet</welcome-file></欢迎文件列表>

servlet在web.xml中的声明和映射如下:

<servlet><servlet-name>HomeServlet</servlet-name><servlet-class>com.brianblog.frontend.HomeServlet</servlet-class></servlet><servlet 映射><servlet-name>HomeServlet</servlet-name><url-模式>/</url-模式></servlet 映射>

<小时>

更新 2:我终于找到了问题 - 我的 servlet 映射不正确.显然,当将 Servlet 设置为 <welcome-file> 时,它不能有 / 的 URL 模式,我觉得这有点奇怪,因为那不是代表网站的根目录?

新的映射如下:

<servlet-mapping><servlet-name>HomeServlet</servlet-name><url-pattern>/HomeServlet</url-pattern></servlet 映射>

解决方案

JSP文件生成的HTML页面中的所有相对URL都是相对于当前请求URL(浏览器地址栏中的URL),not 到您似乎期望的服务器端 JSP 文件的位置.即必须通过 URL 单独下载这些资源的网络浏览器,而不是必须以某种方式从磁盘包含它们的网络服务器.

除了更改相对 URL 以使它们相对于 servlet 的 URL 而不是 JSP 文件的位置之外,解决此问题的另一种方法是使它们相对于域根目录(即以 /).这样,当您更改 servlet 的 URL 时,您无需担心再次更改相对路径.

<head><link rel="样式表";href=/context/css/default.css"/><script src=>/context/js/default.js></script></头><身体><img src="/context/img/logo.png"/><a href="/context/page.jsp">链接</a><form action="/context/servlet"><input type="submit"/></form></身体>

但是,您可能不希望对上下文路径进行硬编码.很合理.您可以通过${pageContext.request.contextPath}获取EL中的上下文路径.

<head><link rel="样式表";href=${pageContext.request.contextPath}/css/default.css"/><script src="${pageContext.request.contextPath}/js/default.js></script></头><身体><img src="${pageContext.request.contextPath}/img/logo.png"/><a href="${pageContext.request.contextPath}/page.jsp">链接</a><form action="${pageContext.request.contextPath}/servlet"><input type="submit"/></form></身体>

(可以通过 轻松缩短并使用作为 ${root} 在别处)

或者,如果您不担心不可读的 XML 和损坏的 XML 语法突出显示,请使用 的帮助.p>

<%@taglib prefix="c"uri=http://java.sun.com/jsp/jstl/core"%><%@taglib 前缀=fn"uri=http://java.sun.com/jsp/jstl/functions"%><c:set var="req";值=${pageContext.request}"/><c:set var="uri";值=${req.requestURI}"/><c:set var="url">${req.requestURL}</c:set>...<头><base href="${fn:substring(url, 0, fn:length(url) - fn:length(uri))}${req.contextPath}/"/><link rel="样式表";href="css/default.css";/><script src="js/default.js"></script></头><身体><img src=img/logo.png";/><a href="page.jsp">链接</a><form action="servlet"><input type="submit"/></form></身体>

这反过来又(再次)有一些警告.锚点(#identifier URL)也将相对于基本路径!您希望将其设置为相对于请求 URL (URI).所以,改变喜欢

<a href="#identifier">跳转</a>

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

每种方式都有其优点和缺点.由您决定选择哪个.至少,你现在应该明白这个问题是如何引起的以及如何解决它了:)

另见:

  • 是否推荐使用<base> html标签?

I'm having trouble with loading CSS and images and creating links to other pages when I have a servlet forward to a JSP. Specifically, when I set my <welcome-file> to index.jsp, the CSS is being loaded and my images are being displayed. However, if I set my <welcome-file> to HomeServlet which forwards control to index.jsp, the CSS is not being applied and my images are not being displayed.

My CSS file is in web/styles/default.css.
My images are in web/images/.

I'm linking to my CSS like so:

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

I'm displaying my images as follows:

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

How is this problem caused and how can I solve it?


Update 1: I've added the structure of the application, as well as some other information that might help.

The header.jsp file is the file that contains the link tag for the CSS. The HomeServlet is set as my welcome-file in web.xml:

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

The servlet is declared and mapped as followes in the 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>


Update 2: I found the problem finally - my servlet was mapped incorrectly. Apparently when setting a Servlet as your <welcome-file> it can't have a URL pattern of /, which I find sort of weird, because wouldn't that stand for the root directory of the site?

The new mapping is as follows:

<servlet-mapping>
    <servlet-name>HomeServlet</servlet-name>
    <url-pattern>/HomeServlet</url-pattern>
</servlet-mapping>

解决方案

All relative URLs in the HTML page generated by the JSP file are relative to the current request URL (the URL as you see in the browser address bar) and not to the location of the JSP file in the server side as you seem to expect. It's namely the webbrowser who has to download those resources individually by URL, not the webserver who has to include them from disk somehow.

Apart from changing the relative URLs to make them relative to the URL of the servlet instead of the location of the JSP file, another way to fix this problem is to make them relative to the domain root (i.e. start with a /). This way you don't need to worry about changing the relative paths once again when you change the URL of the 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>

However, you would probably like not to hardcode the context path. Very reasonable. You can obtain the context path in EL by ${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>

(which can easily be shortened by <c:set var="root" value="${pageContext.request.contextPath}" /> and used as ${root} elsewhere)

Or, if you don't fear unreadable XML and broken XML syntax highlighting, 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>

Either way, this is in turn pretty cumbersome if you have a lot of relative URLs. For that you can use the <base> tag. All relative URL's will instantly become relative to it. It has however to start with the scheme (http://, https://, etc). There's no neat way to obtain the base context path in plain EL, so we need a little help of JSTL here.

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

This has in turn (again) some caveats. Anchors (the #identifier URL's) will become relative to the base path as well! You would like to make it relative to the request URL (URI) instead. So, change like

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

to

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

Each way has its own pros and cons. It's up to you which to choose. At least, you should now understand how this problem is caused and how to solve it :)

See also:

  • Is it recommended to use the <base> html tag?

相关文章