我对node.js很新,我将它用作服务器从浏览器接收http.get请求,进行一些处理并将结果返回给浏览器。
处理实际上是使用phantom.js / casper.js抓取网站,并且由于在node.js中使用casper.js的复杂性,我使用shell脚本将其作为子进程执行。
当我运行下面的代码并从浏览器发出请求时,响应似乎在shell脚本运行之前出现。我尝试使用异步库来运行系列中的步骤,以便run.sh运行并在它添加到响应之前返回一个值,但它似乎不像那样工作。谁能发现我的愚蠢错误?
提前致谢!
var express = require('express');
var app = express();
var sys = require('sys');
var exec = require('child_process').exec;
var async = require('async');
var auth = express.basicAuth('test', 'pass');
var server = app.listen(3000, function() {
console.log('Listening on port %d', server.address().port);
});
var result;
//app.use(auth);
app.get('/free/:u/:p', auth, function(req, res) {
async.series([
function(callback){
var puts = function (error, stdout, stderr) {
result = stdout;
}
exec("./run.sh " + req.params.u + " " + req.params.p, puts);
callback(null);
},
function(callback){
res.writeHead(200,{'Content-Type':'application/json'});
res.send(result)
callback(null);
}
]);
});
app.get('/', function(req, res) {
res.send('Hello!');
});
答案 0 :(得分:0)
您没有异步调用callback(null)
。您需要将其放入puts
。
此外,您不应该使用全局results
变量(它甚至可以跨请求进行全局变换,可能会将数据泄露给不同的客户端 - 唉!)。并且没有理由在这个简单的链条中使用async.js。
app.get('/free/:u/:p', auth, function(req, res) {
exec("./run.sh " + req.params.u + " " + req.params.p, function (error, stdout, stderr) {
res.writeHead(200,{'Content-Type':'application/json'});
res.send(stdout);
});
});
请注意不转义shell参数引入的安全问题。
答案 1 :(得分:0)
基本上你遇到的问题是你正在调用exec
,好像它是一个同步函数,实际上它是异步的。
所以你应该这样做:
exec("./run.sh " + req.params.u + " " + req.params.p, puts, function(){
callback(null);
});
或者只是这样做,因为无论如何你都不会关心异步系列中函数传递的函数参数。
exec("./run.sh " + req.params.u + " " + req.params.p, puts, callback)
答案 2 :(得分:0)
原因是你运行shell命令然后立即调用运行下一个函数(响应)的回调。
要解决此问题,您可以像这样更改置位函数puts
并移除callback(null)
:
var express = require('express');
var app = express();
var sys = require('sys');
var exec = require('child_process').exec;
var async = require('async');
var auth = express.basicAuth('test', 'pass');
var server = app.listen(3000, function() {
console.log('Listening on port %d', server.address().port);
});
var result;
//app.use(auth);
app.get('/free/:u/:p', auth, function(req, res) {
async.series([
function(callback){
var puts = function (error, stdout, stderr) {
result = stdout;
callback(null); //added here
}
exec("./run.sh " + req.params.u + " " + req.params.p, puts);
//callback(null); //commented
},
function(callback){
res.writeHead(200,{'Content-Type':'application/json'});
res.send(result)
callback(null);
}
]);
});
app.get('/', function(req, res) {
res.send('Hello!');
});
虽然这种方法有效,但最好使用async.waterfall
代替async.series
。它允许您将每个函数的结果传递给下一个函数。因此,您不需要拥有全局result
变量。