我有几个WebSockets端点,如,
wss://localhost:8181/ContextPath/Push
Run Code Online (Sandbox Code Playgroud)
所有这些端点URL都在单独的外部JavaScript文件中进行硬编码(.js).这些JavaScript文件在需要时包含在各自的XHTML文件中.应该以编程方式评估主机名和上下文路径,而不是在需要它们的地方进行硬编码.
主机名(localhost:8181)可以使用JavaScript获得,document.location.host但JavaScript 中没有标准/规范方式来获取应用程序运行的上下文路径.
我正在做类似以下的事情.
在主模板上声明全局JavaScript变量,如下所示.
<f:view locale="#{bean.locale}" encoding="UTF-8" contentType="text/html">
<f:loadBundle basename="messages.ResourceBundle" var="messages"/>
<ui:param name="contextPath" value="#{request.contextPath}"/>
<ui:insert name="metaData"></ui:insert>
<h:head>
<script type="text/javascript">var contextPath = "#{contextPath}";</script>
</h:head>
<h:body id="body">
</h:body>
</f:view>
</html>
Run Code Online (Sandbox Code Playgroud)
其中主机名和上下文路径被硬编码的JavaScript文件包括在相应的模板客户端或模板的北,南,东和西的任何部分中,如下所述.
<html lang="#{bean.language}"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:form>
<h:outputScript library="default" name="js/websockets.js" target="head"/>
</h:form>
Run Code Online (Sandbox Code Playgroud)
仅为了观点,websockets.js看起来如下(你可以简单地忽略它).
if (window.WebSocket) {
// The global variable "contextPath" is unavailable here
// because it is declared afterwards in the generated HTML.
var ws = new WebSocket("wss://"+document.location.host + contextPath + "/Push");
ws.onmessage = function (event) {
// This handler is invoked, when a message is received through a WebSockets channel.
};
$(window).on('beforeunload', function () {
ws.close();
});
} else {}
Run Code Online (Sandbox Code Playgroud)
现在,contextPath主模板中声明的全局JavaScript变量应该在包含的JavaScript文件中可用websockets.js.然而,这是不真实的.
所发生的是包含的JavaScript文件,即尝试访问websockets.js全局变量的contextPath位置,放在主模板中生成的HTML 标记中的硬编码标记之前.<script><head>
换句话说,全局JavaScript变量contextPath实际上是websockets.js在声明之前尝试在包含的文件中使用.
无论如何,如何摆脱外部JavaScript文件中的硬编码上下文路径?
这样做的唯一目的是,与CSS文件不同,EL不在外部JavaScript文件中进行评估.因此,#{}除非将其放在XHTML文件中,否则它将无法工作.
所发生的是,包含的JavaScript文件命名为尝试访问
websockets.js全局变量的contextPath位置,它位于主模板中生成的HTML 标记中的硬编码标记之前<script><head>
这是出乎意料的.你声明的<h:outputScript>引用websockets.js内部文件<h:body>用target="head".这应该在已经声明的所有其他脚本资源之后结束<h:head>.另请参阅ao 如何在Facelets模板中引用CSS/JS /图像资源?毕竟,这似乎是由捆绑的PrimeFaces引起的,HeadRenderer它意图自动包含一些CSS资源并照顾好<facet name="first|middle|last">.
这对PF人来说是值得的问题报告(如果还没有完成的话).同时,最好的办法是通过显式注册JSF实现自己的HeadRenderer后面来关闭它faces-config.xml(如果您使用的是Mojarra).
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.Head</renderer-type>
<renderer-class>com.sun.faces.renderkit.html_basic.HeadRenderer</renderer-class>
</renderer>
</render-kit>
Run Code Online (Sandbox Code Playgroud)
并明确包括PrimeFaces主题特定theme.css如下<h:head>:
<h:outputStylesheet library="primefaces-aristo" name="theme.css" />
Run Code Online (Sandbox Code Playgroud)
回到真正的问题,
无论如何,如何摆脱外部JavaScript文件中的硬编码上下文路径?
将其设置为基本URI(注意:HTML4/IE6-8中不支持相对路径).
<h:head>
<base href="#{request.contextPath}/" />
...
</h:head>
Run Code Online (Sandbox Code Playgroud)
var baseURI = $("base").attr("href");
Run Code Online (Sandbox Code Playgroud)
或者将其设置为HTML根元素的数据属性.
<!DOCTYPE html>
<html lang="en" data-baseuri="#{request.contextPath}/" ...>
...
</html>
Run Code Online (Sandbox Code Playgroud)
var baseURI = $("html").data("baseuri");
Run Code Online (Sandbox Code Playgroud)
与具体问题无关,作为建议,透明地涵盖http + ws和https + wss,考虑使用location.protocol而不是硬编码wss.
var ws = new WebSocket(location.protocol.replace("http", "ws") + "//" + location.host + baseURI + "Push");
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2063 次 |
| 最近记录: |