我有一个快速应用程序,我想使用连接表单模块来处理一些文件上传表单。我按照快速GitHub仓库和连接表单中的示例进行操作,但是当我调用req.form.complete(function(){})
时,我收到了一个错误Cannot call method 'complete' of undefined
。这是我的代码:
var express = require('express'),
knox = require('knox'),
form = require('connect-form')/*,
controller = require('controller').Controller*/;
var app = module.exports = express.createServer();
// Configuration
var port = process.env.PORT || 3000;
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
form({ keepExtensions: true });
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', function(req, res){
res.render('index', {
title: 'Express'
});
});
app.get('/manage/new', function(req, res){
res.render('manage/new', {
title: 'Create a new widget'
});
});
app.post('/manage/new', function(req, res, next){
if(!req.form){
res.send('Form not submitted.', {'Content-Type': 'text/plain'}, 500);
console.log(req);
}
else{
req.form.complete(function(err, fields, files){
if(err) next(err);
else {
console.log('\nuploaded %s to %s', files.download.filename, files.download.path);
res.redirect('back');
}
});
console.log(req.form);
}
});
app.listen(port);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
我的Jade模板:
h1= title
#wrapper
#main
form(method="post", enctype="multipart/form-data", name="create-widget")
.errors
fieldset
legend Band / Album Information
p
label.tooltip(for="txtTitle", data-tooltip="Band name or title to use on widget.") Band Name
br
input#txtTitle.input_full(name="title", placeholder="The Beatles")
p
label.tooltip(for="txtAlbum", data-tooltip="Album title shown on widget") Album
br
input#txtAlbum.input_full(name="album", placeholder="Magical Mystery Tour")
p
label.tooltip(for="fileDownload", data-tooltip="File to be downloaded after submitting form on Widget") Download
br
input#fileDownload.input_full(name="download", type="file")
#actions
input(type="submit", value="Generate Widget")
我的代码有问题吗?另外,在上传下载字段时,我实际上希望将文件直接上传到S3存储桶。我是否可以在上传流时访问该流,以便让上传速度更快?
修改
以下是我提交表单时req对象的内容:
{ socket:
{ bufferSize: 0,
fd: 6,
type: 'tcp4',
allowHalfOpen: true,
_readWatcher:
{ socket: [Circular],
callback: [Function: onReadable] },
destroyed: false,
readable: true,
_writeQueue: [],
_writeQueueEncoding: [],
_writeQueueFD: [],
_writeQueueCallbacks: [],
_writeWatcher:
{ socket: [Circular],
callback: [Function: onWritable] },
writable: true,
_writeImpl: [Function],
_readImpl: [Function],
_shutdownImpl: [Function],
remoteAddress: '127.0.0.1',
remotePort: 51588,
server:
{ stack: [Object],
connections: 1,
allowHalfOpen: true,
watcher: [Object],
_events: [Object],
httpAllowHalfOpen: false,
cache: {},
settings: [Object],
redirects: {},
isCallbacks: {},
_locals: [Object],
dynamicViewHelpers: {},
errorHandlers: [],
route: '/',
routes: [Object],
router: [Getter],
__usedRouter: true,
type: 'tcp4',
fd: 7 },
ondrain: [Function],
_idleTimeout: 120000,
_idleNext:
{ repeat: 120,
_idleNext: [Circular],
_idlePrev: [Circular],
callback: [Function] },
_idlePrev:
{ repeat: 120,
_idleNext: [Circular],
_idlePrev: [Circular],
callback: [Function] },
_idleStart: Fri, 21 Oct 2011 16:08:07 GMT,
_events:
{ timeout: [Function],
error: [Function],
close: [Function] },
ondata: [Function],
onend: [Function],
_httpMessage: null },
connection:
{ bufferSize: 0,
fd: 6,
type: 'tcp4',
allowHalfOpen: true,
_readWatcher:
{ socket: [Circular],
callback: [Function: onReadable] },
destroyed: false,
readable: true,
_writeQueue: [],
_writeQueueEncoding: [],
_writeQueueFD: [],
_writeQueueCallbacks: [],
_writeWatcher:
{ socket: [Circular],
callback: [Function: onWritable] },
writable: true,
_writeImpl: [Function],
_readImpl: [Function],
_shutdownImpl: [Function],
remoteAddress: '127.0.0.1',
remotePort: 51588,
server:
{ stack: [Object],
connections: 1,
allowHalfOpen: true,
watcher: [Object],
_events: [Object],
httpAllowHalfOpen: false,
cache: {},
settings: [Object],
redirects: {},
isCallbacks: {},
_locals: [Object],
dynamicViewHelpers: {},
errorHandlers: [],
route: '/',
routes: [Object],
router: [Getter],
__usedRouter: true,
type: 'tcp4',
fd: 7 },
ondrain: [Function],
_idleTimeout: 120000,
_idleNext:
{ repeat: 120,
_idleNext: [Circular],
_idlePrev: [Circular],
callback: [Function] },
_idlePrev:
{ repeat: 120,
_idleNext: [Circular],
_idlePrev: [Circular],
callback: [Function] },
_idleStart: Fri, 21 Oct 2011 16:08:07 GMT,
_events:
{ timeout: [Function],
error: [Function],
close: [Function] },
ondata: [Function],
onend: [Function],
_httpMessage: null },
httpVersion: '1.1',
complete: false,
headers:
{ host: '127.0.0.1:5000',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:6.0) Gecko/20100101 Firefox/6.0',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'accept-language': 'en-us,en;q=0.5',
'accept-encoding': 'gzip, deflate',
'accept-charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
connection: 'keep-alive',
referer: 'http://127.0.0.1:5000/manage/new',
'content-type': 'multipart/form-data; boundary=---------------------------20072377098235644401115438165',
'content-length': '247075' },
trailers: {},
readable: true,
url: '/manage/new',
method: 'POST',
statusCode: null,
client:
{ bufferSize: 0,
fd: 6,
type: 'tcp4',
allowHalfOpen: true,
_readWatcher:
{ socket: [Circular],
callback: [Function: onReadable] },
destroyed: false,
readable: true,
_writeQueue: [],
_writeQueueEncoding: [],
_writeQueueFD: [],
_writeQueueCallbacks: [],
_writeWatcher:
{ socket: [Circular],
callback: [Function: onWritable] },
writable: true,
_writeImpl: [Function],
_readImpl: [Function],
_shutdownImpl: [Function],
remoteAddress: '127.0.0.1',
remotePort: 51588,
server:
{ stack: [Object],
connections: 1,
allowHalfOpen: true,
watcher: [Object],
_events: [Object],
httpAllowHalfOpen: false,
cache: {},
settings: [Object],
redirects: {},
isCallbacks: {},
_locals: [Object],
dynamicViewHelpers: {},
errorHandlers: [],
route: '/',
routes: [Object],
router: [Getter],
__usedRouter: true,
type: 'tcp4',
fd: 7 },
ondrain: [Function],
_idleTimeout: 120000,
_idleNext:
{ repeat: 120,
_idleNext: [Circular],
_idlePrev: [Circular],
callback: [Function] },
_idlePrev:
{ repeat: 120,
_idleNext: [Circular],
_idlePrev: [Circular],
callback: [Function] },
_idleStart: Fri, 21 Oct 2011 16:08:07 GMT,
_events:
{ timeout: [Function],
error: [Function],
close: [Function] },
ondata: [Function],
onend: [Function],
_httpMessage: null },
httpVersionMajor: 1,
httpVersionMinor: 1,
upgrade: false,
originalUrl: '/manage/new',
query: {},
app:
{ stack:
[ [Object],
[Object],
[Object],
[Object],
[Object],
[Object] ],
connections: 1,
allowHalfOpen: true,
watcher: { host: [Circular], callback: [Function] },
_events:
{ request: [Function],
connection: [Function: connectionListener],
listening: [Function] },
httpAllowHalfOpen: false,
cache: {},
settings:
{ env: 'development',
hints: true,
views: '/Users/davejlong/Workspace/Node/Widget/views',
'view engine': 'jade' },
redirects: {},
isCallbacks: {},
_locals: { settings: [Object], app: [Circular] },
dynamicViewHelpers: {},
errorHandlers: [],
route: '/',
routes:
{ app: [Circular],
routes: [Object],
params: {},
_params: [],
middleware: [Function] },
router: [Getter],
__usedRouter: true,
type: 'tcp4',
fd: 7 },
res:
{ output: [],
outputEncodings: [],
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
_hasBody: true,
_trailer: '',
finished: true,
socket: null,
connection: null,
_events: { finish: [Function] },
_headers:
{ 'x-powered-by': 'Express',
'content-type': 'text/plain; charset=utf-8',
'content-length': 19 },
_headerNames:
{ 'x-powered-by': 'X-Powered-By',
'content-type': 'Content-Type',
'content-length': 'Content-Length' },
app:
{ stack: [Object],
connections: 1,
allowHalfOpen: true,
watcher: [Object],
_events: [Object],
httpAllowHalfOpen: false,
cache: {},
settings: [Object],
redirects: {},
isCallbacks: {},
_locals: [Object],
dynamicViewHelpers: {},
errorHandlers: [],
route: '/',
routes: [Object],
router: [Getter],
__usedRouter: true,
type: 'tcp4',
fd: 7 },
req: [Circular],
charset: 'utf-8',
statusCode: 500,
_header: 'HTTP/1.1 500 Internal Server Error\r\nX-Powered-By: Express\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 19\r\nConnection: keep-alive\r\n\r\n',
_headerSent: true },
next: [Function: next],
originalMethod: 'POST',
_route_index: 0,
route:
{ path: '/manage/new',
method: 'post',
callbacks: [ [Function] ],
keys: [],
regexp: /^\/manage\/new\/?$/i,
params: [] },
params: [] }
答案 0 :(得分:0)
猜猜表单不是从浏览方提交的,请参阅http://visionmedia.github.com/connect-form/
上提供的示例 var form = require('connect-form');
var server = connect.createServer(
form({ keepExtensions: true }),
function(req, res, next){
// Form was submitted
if (req.form) {
// Do something when parsing is finished
// and respond, or respond immediately
// and work with the files.
req.form.onComplete = function(err, fields, files){
res.writeHead(200, {});
if (err) res.write(JSON.stringify(err.message));
res.write(JSON.stringify(fields));
res.write(JSON.stringify(files));
res.end();
};
// Regular request, pass to next middleware
} else {
next();
}
}
);
示例中的“if(req.form)”确保表单确实已提交!您应该这样做,因为您可能无法控制发布到您的API的内容!!
答案 1 :(得分:0)
我不确定为什么连接表单不起作用,但是我发现它是在Formidable模块的顶部写的,所以我把它拿到了我的路由器中然后用它来正确地拾取表单:
var sys = require('sys'),
express = require('express'),
knox = require('knox'),
formidable = require('formidable'),
controller = require('./controller').Controller;
var app = module.exports = express.createServer();
/* ================================================================ */
/* Configuration */
/* ================================================================ */
var port = process.env.PORT || 3000;
var hostName = 'http://download.comeandlive.com';
controller.setup(hostName, 80);
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
/* ================================================================ */
/* Routes */
/* ================================================================ */
app.get('/', function(req, res){
res.redirect('http://comeandlive.com', 301);
});
/* ================================ */
/* Administration Routes */
/* ================================ */
app.get('/manage', function(req, res){
res.render('manage/index', {
title: 'Widget Administration'
});
})
app.get('/manage/new', function(req, res){
res.render('manage/new', {
title: 'Create a new widget'
});
});
app.post('/manage/new', function(req, res, next){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files){
res.header('Content-Type', 'text/plain');
res.send('Received upload:\n\n' + sys.inspect({fields:fields, files:files}));
});
});
app.listen(port);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);