为什么我的 EL 语句只在我不通过 src 引用导入 js.file 的脚本标签中工作?

Why is my EL-statement only working in a script-tag where I do not import a js.file through a src-reference?

我有一个 javascript 文件,我在其中收集了需要在我的 Web 应用程序的所有页面上可用的登录和其他用户配置文件 ajax 调用。

对于我所有的 ajax 调用,我需要 webapp 的上下文路径才能获得正确的 URL。 baseUrl 变量可以定义为 var baseUrl = "${pageContext.request.contextPath}";.

不过我遇到了一个令人费解的错误。如果我尝试在我的 login.js 文件中初始化 baseUrl 变量,它不起作用。它只是设置为字符串值 "${pageContext.request.contextPath}" 这个 .js 文件包含我实际需要变量的所有脚本。但是,如果我在 .jsp 文件本身的无源脚本标签内定义它,它就像一个魅力。 (代码在底部)

我猜测这与表达式编译的时间和范围有关 and/or 执行,也可能与代码的动态和静态导入之间的区别有关。我只是无法完全理解正在发生的事情,以及为什么我想要的方法(在 login.js 文件中定义变量)不起作用。

工作导入语句:

<script>var baseUrl = "${pageContext.request.contextPath}";</script>
<script src="<c:url value="/js/login.js"/>" type="text/javascript"></script>

EL 表达式仅由具有此功能的 servlet 求值。此类 servlet 的示例有 JSP's JspServlet and JSF's FacesServlet。一个能够计算模板文本中的 ${...},另一个能够计算模板文本中的 ${...}#{...}。容器的默认 servlet 负责静态资源,如 *.js 文件。

鉴于您正在使用 JSP,只需告诉您的网络应用程序使用 JspServlet 来处理任何 *.js 请求。容器的内置 JspServlet 通常有一个默认的 servlet 名称 jsp (至少,对于 Tomcat 和克隆是这样),所以你的 webapp 的 web.xml 中的下面条目应该做为了让 EL 在 *.js 文件中进行评估。

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>

不过这有一个小警告。一些容器强行将内容类型 header 更改为 text/html 而不管 js 文件扩展名,然后浏览器在下载 JS 文件时感到困惑。防止这种情况的一种方法是在 JS 文件顶部以 JSP 方式显式设置所需的内容类型 header:

<%@page contentType="application/javascript" %>

一个完全不同的替代方法是将上下文路径打印为 <html> 标记的 HTML5 数据属性。

<!DOCTYPE html>
<html lang="en" data-baseuri="${pageContext.request.contextPath}/">
    ...
</html>

然后它就可以在 JS 中的任何地方使用,如下所示:

var baseuri = document.documentElement.dataset.baseuri;

或者如果您是 jQuery 粉丝:

var baseuri = $("html").data("baseuri");