使用 Express 从本地主机获取数据/将数据写入本地主机
Posted
技术标签:
【中文标题】使用 Express 从本地主机获取数据/将数据写入本地主机【英文标题】:Getting data from/writing data to localhost with Express 【发布时间】:2017-09-15 21:34:16 【问题描述】:我正在尝试使用 node (w/npm) 和 express 为网络艺术类创建一个 webapp。这个想法是让网站的主体都是一种颜色,但是任何人都可以在 Twilio 编号处向网站发送十六进制代码/CSS 颜色,并且网站的颜色将立即更改为该颜色值。
它的工作原理基本上是服务器在http://example.com/message 接收来自 Twilio 的 POST 请求,其中包含文本消息的正文。它将它写入到 ~/app/.data/color.tmp 的临时文件中,客户端通过 jQuery .get() 调用 http://example.com/color 来访问该文件,并返回
所以问题来了:我有一个在 glitch.me 上运行的应用程序版本,所以我知道这段代码可以运行,但我很难让它在我的域上运行。我安装了该应用程序并可以使用 npm 启动它,它成功地向我显示了 html 页面,但 Chrome 开发工具显示脚本在尝试访问 /color 时收到 403。此外,我网站的新文本不会更改 /.data/color.tmp 中的颜色值。我认为这可能是权限问题,但我检查了它们,它们看起来很好。
这是 index.html 页面上的服务器文件和脚本:
app/server.js
var express = require('express');
var bodyParser = require('body-parser');
var fs = require('fs');
var app = express();
app.use(bodyParser.urlencoded(extended: false));
var dataPath = '.data/color.tmp';
// set a new color (saves posted color to disk)
app.post("/message", function (request, response)
var dataStr = JSON.stringify(request.body.Body);
fs.writeFile(dataPath, dataStr);
response.end();
);
// get the saved color (reading from disk)
app.get("/color", function (request, response)
var dataStr = fs.readFileSync(dataPath).toString();
response.send(JSON.parse(dataStr));
);
app.get("/", function (request, response)
response.sendFile(__dirname + '/views/index.html');
);
var listener = app.listen(process.env.PORT, function ()
console.log('listening on port ' + listener.address().port);
);
app/views/index.html
<script>
// checks server for color value and sets background
function checkForColorChange()
$.get('/color', function getColorComplete(data)
document.body.style.backgroundColor = data;
console.log(data);
)
// Poll the server at 2000ms interval
setInterval(checkForColorChange, 2000);
checkForColorChange();
</script>
无论如何,如果它在 Glitch 上如此轻松地运行并且不会在我的网站上运行,我觉得我一定错过了一些非常明显的东西,但我已经被困了几天并且没有取得任何进展!任何帮助将不胜感激。如果还有什么不清楚的,请告诉我。
【问题讨论】:
在您的服务器上运行应用程序的用户是否有权读取/写入data/color.tmp
?
@dan 是的,我刚刚检查过,它正在通过我的用户帐户上的一个屏幕运行,该屏幕应该具有完整的 r/w 权限。 imgur.com/a/FqFE4
@wombevyn 你看到下面my answer 的更新了吗?它包括一个您想要在此处实现的工作示例,并带有用于快速测试的source code on GitHub 和Deploy to Heroku 选项。我想知道你是否在演示中使用过它,是否有任何关于它的 cmets。
【参考方案1】:
(有关工作示例,请参阅下面的更新)
TL;DR - 示例:
原答案
您的代码存在一些问题:
-
您没有检查错误
您正在使用阻塞函数
你隐式依赖文件权限,但你没有检查它
您正在使用字符串连接而不是
path.join
来连接路径
您一直在轮询新数据,而不是等待它改变
您没有捕获可能引发异常的函数的异常
您无需等待异步操作完成,也无需处理错误
您现在遇到的主要问题很可能与文件权限有关。好消息是,您不需要任何文件访问权限来执行您正在做的事情,并且为此使用文件也不是最佳选择。您只需将颜色存储在一个变量中,如果您不需要它,它会在服务器重新启动之间持续存在 - 即使您这样做了,我也会为此使用一个简单的数据库。
例如:
// some initial value:
var color = '#ffffff';
app.post("/message", function (request, response)
var color = request.body.Body;
response.end();
);
// get the saved color (reading from disk)
app.get("/color", function (request, response)
response.send(color);
);
app.get("/", function (request, response)
response.sendFile(__dirname + '/views/index.html');
);
var listener = app.listen(process.env.PORT, function ()
console.log('listening on port ' + listener.address().port);
);
这是我将使用的第一个更改 - 不要依赖文件系统、权限、竞争条件等。
您的代码遇到的另一个问题是在请求处理程序中使用阻塞函数。除了事件循环的第一个滴答声之外,您不应该使用任何阻塞函数(名称中带有“Sync”的函数)。
我要做的另一项改进是使用 WebSocket 或 Socket.io,而不是定期轮询数据。这将很容易编码。有关示例,请参见此答案:
Differences between socket.io and websockets这样做的好处是,您的所有学生都会立即同时改变颜色,而不是在 2 秒内随机改变颜色。
更新
我写了一个我上面描述的例子。
POST 端点稍有不同 - 它使用 /color
路由和 color=#abcdef
而不是 /message
和 Body=...
,但您可以根据需要轻松更改它 - 见下文。
服务器代码 - server.js:
// requires removed for brevity
const app = express();
const server = http.Server(app);
const io = socket(server);
let color = '#ffffff';
app.use(bodyParser.urlencoded( extended: false ));
app.use('/', express.static(path.join(__dirname, 'html')));
io.on('connection', (s) =>
console.log('Socket.io client connected');
s.emit('color', color);
);
app.post('/color', (req, res) =>
color = req.body.color;
console.log('Changing color to', color);
io.emit('color', color);
res.send( color );
);
server.listen(3338, () => console.log('Listening on 3338'));
HTML 页面 - index.html:
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width, initial-scale=1">
<title>Node Live Color</title>
<link href="/style.css" rel=stylesheet>
</head>
<body>
<h1>Node Live Color</h1>
<script src="/socket.io/socket.io.js"></script>
<script src="/script.js"></script>
</body>
</html>
样式表-style.css:
body
transition: background-color 2s ease;
background-color: #fff;
客户端 javascript - script.js:
var s = io();
s.on('color', function (color)
document.body.style.backgroundColor = color;
);
特别有趣的是客户端代码非常简单。
对于您的原始端点,请在 server.js 中使用:
app.post('/message', (req, res) =>
color = req.body.Body;
console.log('Changing color to', color);
io.emit('color', color);
res.end();
);
GitHub 上提供了完整示例:
https://github.com/rsp/node-live-color我在本地和 Heroku 上对其进行了测试。您可以单击此按钮将其部署到 Heroku 上并自行测试:
享受吧。
【讨论】:
非常感谢您提供如此详细的反馈,不确定我是否有时间在项目中实现 socket.io,但我会看看并试一试。我从试图访问 /color 的客户端脚本中不断收到 403 错误怎么办?我需要有一个“/public_html/color”文件夹吗? @wombevyn 我用 Socket.io 写了一个完整的工作示例 - 请参阅我更新的答案。 @wombevyn 你看到更新的答案了吗?对你起作用吗?有cmets吗? 它完全适合我!做得非常好,非常感谢您抽出宝贵的时间来制作它——我将它连接到 Twilio 号码上,并从我的手机发送了一些颜色。你写的时候还在课堂上展示了这个演示,抱歉我花了这么长时间才回复。【参考方案2】:我认为,问题出在var dataStr = fs.readFileSync(dataPath).toString();
。请更改您的dataPath
如下:
var dataPath = __dirname + '/data/color.tmp';
并且还要确保该文件具有读/写权限。
【讨论】:
以上是关于使用 Express 从本地主机获取数据/将数据写入本地主机的主要内容,如果未能解决你的问题,请参考以下文章
使用 Angular 和 Spring Boot 从本地主机获取数据
如何从 Express API 获取数据并将其显示到 React 应用程序?
如何将远程 SQL Server Express 数据库的部分副本复制到本地 SQL Server Express 数据库?