使用 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 而不是 /messageBody=...,但您可以根据需要轻松更改它 - 见下文。

服务器代码 - 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 从本地主机获取数据

Fetch Api:无法从本地主机获取数据

从Angular中的不同本地主机获取数据

如何从 Express API 获取数据并将其显示到 React 应用程序?

如何将远程 SQL Server Express 数据库的部分副本复制到本地 SQL Server Express 数据库?

尝试从反应应用程序的本地主机 Web api 端点获取数据 - Cors 错误