我有一个相当复杂的设置,需要Web浏览器本地存储已填充计算机的名称,以便应用程序正常工作。为此,我从配置文件中读取:
kiosk-name: Mort
我在启动node.js web服务器时读取配置文件:
var filesys = require('fs');
var os = require('os');
filesys.readFile(project_path + '/kiosk.cfg', 'utf8', function(err, data) {
var kioskname;
if (err) {
//console.log(err);
kioskname = os.hostname();
} else {
var configArray = data.split(':');
if('' != configArray[1]) {
kioskname = configArray[1];
} else {
kioskname = os.hostname();
}
}
});
所有这些都按设计工作,在未填充配置文件时使用计算机的os.hostname()
作为默认设置。
客户端具有基页(index.html),可将默认页面(default.html)加载到iframe
。基于websocket消息传递系统,默认页面被远程IP中的另一个页面替换。 在旧版本的系统中(在实现配置文件之前),我们可以使用以下代码设置本地存储元素:
var win = document.getElementsByTagName('iframe')[0].contentWindow;
win.postMessage(JSON.stringify({key: 'kiosk-name', data: kioskName}), "*");
我们在收到websocket消息时识别iframe,然后发送包含JSON字符串的帖子消息来设置本地存储元素。在这种情况下,kioskName
是包含硬编码值的变量。
问题
现在我们希望从配置文件中读取值,我们需要一种方法将kioskname
传递给客户端JavaScript,以便我们可以在iframe
中设置本地存储元素。
我尝试将文件读取功能放在export
包装器中:
(function(exports){
// file reading code here
return kioskname;
})(typeof exports === 'undefined' ? this['kioskname']={} : exports);
我收到了一个错误:
未捕获的ReferenceError:未定义require
在export
函数中放置一个静态值(在require
之外)允许导出函数正常工作,但是不允许我读取需要两个{的配置文件{1}}和os
个模块。
如何从配置文件返回的值到我可以在客户端使用它来设置本地存储元素的地方?
答案 0 :(得分:1)
这是一个创造性的解决方案,可能不适合所有情况,因为它涉及在Node.js Web服务器和客户端之间使用websocket。
Websocket设置发送给客户端(假设网络服务器位于' node_server
':
var io = require('socket.io').listen(node_server); // 'attaches' socket.io to this web server
io.sockets.on('connection', function (socket) {
socket.emit('message', 'socket.io connected'); // output a connection message
// receive JSON message and send to the websocket
socket.on('message', function (data) {
var address = node_server.address();
var client = dgram.createSocket("udp4");
var message = new Buffer(data);
// out of the airlock!
client.send(message, 0, message.length, address.port, address.address, function(err, bytes) {
client.close();
});
});
});
读取配置文件,然后解析并向套接字发送消息(在服务器端完成):
filesys.readFile(project_path + '/kiosk.cfg', 'utf8', function(err, data) {
var kioskname;
if (err) {
//console.log(err);
kioskname = os.hostname();
} else {
var configArray = data.split(':');
if('' != configArray[1]) {
kioskname = configArray[1];
} else {
kioskname = os.hostname();
}
}
// create JSON string for transmission
KioskName = JSON.stringify({'config':{'kiosk-name': kioskname}});
var send_KioskName = setInterval(function(){ // could be a setTimeout for a one time send
io.sockets.emit('message', KioskName.toString()); // send config file data to browser via socket
}, 30000);
});
注意此可以展开,以便在需要时通过JSON向客户端发送多个数据。只需几个小编辑即可设置更详细的JSON对象。
在客户端接收套接字消息(此代码由客户端加载),然后解析。生成的对象将添加到此应用程序的命名空间中,使该对象在需要时可用于多个脚本。
注意:您应该只对不会干扰您可能在脚本中创建或销毁的对象的对象使用此方法。
// make sure a string is JSON before using
function isJSON(str) {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
}
// set up object 'array's
var kioskname = {};
// connect a socket to listen for incoming messages from the Big Giant Head
var socket = io();
socket.on('message', function (data) {
if(isJSON(data)) {
// parse the json
var json = $.parseJSON(data);
// determine how to use this JSON object, multiple objects may be sent
if('config' == Object.keys(json)[0]) {
/*
* send config data where needed - future proofed, just add cases
* and namespaced objects where required
*/
kioskname['name'] = json.config['kiosk-name'];
}
}
});
// attach objects to namespace
window.KIOSK.kioskname = kioskname;
现在我们可以使用该对象设置本地存储。 在我们的案例中,我们向应用的服务器发布了一条消息,并以localStorage.setItem()
回复:
发布消息:
var currentFrame = document.getElementsByTagName('iframe')[0].contentWindow;
currentFrame.postMessage(JSON.stringify({key: 'user-name', data: KIOSK.kioskname.name}), "*");
通过打开套接字并使用通过套接字传递的JSON字符串来填充命名空间对象,我们可以使用应用程序客户端中配置文件中的服务器端信息。