I try to figure out how to use the defer-property of the bodyParser used in express (and compoundjs) correctly.
The goal is to get access to the event-property which should be possible duo passing the defer-property to the bodyParser.
What happens is, that the bodyParser doesnt work at all for enctype=multipart/form-data.
In my opinion the bodyParser still should parse the request and place all relevant data in the body-Object. But the body-Object is empty for every Request I use a form with enctype=multipart/form-data. That causes several errors like authetification failure or forgery-Check.
So - whats going on here? Did I unserstand something wrong? The bodyParser just should do its job and I want to have access to the progress-event.
PS: I read about errors caused by the order I use bodyParser, sessionParser and so on.
Therefore here is my configuration (compoundjs):
module.exports = function (compound) {
var express = require('express');
var app = compound.app;
app.configure(function(){
app.use(compound.assetsCompiler.init());
app.use(express.static(app.root + '/public', { maxAge: 86400000 }));
app.set('jsDirectory', '/javascripts/');
app.set('cssDirectory', '/stylesheets/');
app.set('cssEngine', 'less');
app.set('view engine', 'ejs');
// make sure you run `npm install browserify uglify-js`
// app.enable('clientside');
app.use(express.methodOverride());
app.use(express.cookieParser('secret'));
app.use(express.session({secret: 'secret'}));
app.use(express.bodyParser({
//keepExtensions: true,
limit: 10000000, // 10M limit
defer: true
}));
app.use(app.router);
});
};
Here is the answer to my own question. I hope it will help poeple with the same problem.
First of all: You cant observe the progress-event of the fileupload in your normal app-code (e.g. controller, model).
I tried to use the before-filter which seemed to work till I realized that it destroys the method-overiding.
Thats why I had to wrote my own very simple middleware which just listens to the progress and end-event of req.form which logs the progress and calls next() when the end-event happens.
module.exports = function (compound) {
var express = require('express');
var app = compound.app;
app.configure(function(){
app.use(compound.assetsCompiler.init());
app.use(express.static(app.root + '/public', { maxAge: 86400000 }));
app.set('jsDirectory', '/javascripts/');
app.set('cssDirectory', '/stylesheets/');
app.set('cssEngine', 'less');
app.set('view engine', 'ejs');
app.use(express.bodyParser({
//keepExtensions: true,
limit: 10000000, // 10M limit
defer: true
}));
// Thats the middleware
app.use(function(req, res, next){
// Only use it if form isnt parsed yet through bodyParser
if(!req.form){next();return;}
req.form.on('progress', function(bytesReceived, bytesExpected) {
console.log('progress: '+Math.round(bytesReceived/bytesExpected*100)+'%');
req.form.on('end',function(){
console.log('fileupload finished');
next();
});
});
app.use(express.cookieParser('secret'));
app.use(express.session({secret: 'secret'}));
app.use(express.methodOverride());
app.use(app.router);
});
};
Its worth to mention that the order of the middleware-calls is very important.
First you have to call the bodyParser (with defer:true).
If that is done the Parser can parse all incoming requests for you and only delegate the forms of enctype="multipart/form-data" to you. Then your middleware can observe the upload.
After that Session and Cookies are loaded. I tried to load the session and cookies before my middleware to know whether the user which is currently uploadind has the right to do so but that caused very wired behavior. I could read the session and all seems great but all my data in the form-object became doubled. {name:'dude'} becamed {name:{0:'dude',1:'dude'}} which destroyed the method-Override, too.
This order is my only known working order.
If you have a solution to the mentioned problem with the doubled data any help would be appreciated :)
//EDIT: I got a solution for the problem above. The Probem was - of couse as always - the order of the middleware. Here again the "final" Code which works with uploadprogress and authentification through session:
module.exports = function (compound) {
var express = require('express');
var app = compound.app;
app.configure(function(){
app.use(compound.assetsCompiler.init());
app.use(express.static(app.root + '/public', { maxAge: 86400000 }));
app.set('jsDirectory', '/javascripts/');
app.set('cssDirectory', '/stylesheets/');
app.set('cssEngine', 'less');
app.set('view engine', 'ejs');
// make sure you run `npm install browserify uglify-js`
// app.enable('clientside');
// At the very first load Cookie and Session
app.use(express.cookieParser('secret'));
app.use(express.session({secret: 'secret'}));
// Load the bodyParer then with defer:true
app.use(express.bodyParser({
//keepExtensions: true,
limit: 10000000, // 10M limit
defer: true
}));
// Now comes the own middleware with access to the session _and_ the progress
app.use(function(req, res, next){
console.log('searching for files to upload...');
if(!req.form || req.form.type != 'multipart'){next();return;}
console.log('check if user is autheticated...');
if(!req.session.userId)
{
console.log('user is not authenticated. Throwing Error to prevent further upload!');
try { throw new Error("Stopping file upload..."); }
catch (e) { res.end(e.toString()); }
next();return;
}
console.log('file found - attaching events...');
req.form.on('progress', function(bytesReceived, bytesExpected) {
console.log('progress: '+Math.round(bytesReceived/bytesExpected*100)+'%');
});
req.form.on('end',function(){
console.log('fileupload finished');
next();
});
});
app.use(express.methodOverride());
app.use(app.router);
});
};
Related
I have been trying to use keycloak authentication and have been stuck on this for a while. This is my code
app.get('/', function(req,res){
res.render('login1');
});
app.get('/login', keycloak.protect(), function (req, res) {
res.render('dashboard', {
result: JSON.stringify(JSON.parse(req.session['keycloak-token']), null, 4)
});
});
So what is happening is, when i go to hostname/login, it redirects me to a login page of my company (we are validating the company employees with their credentials), we have a redirect uri which is http://hostname/login/* , so after keycloak.protect() executes, and user enters his credentials, it goes into infinite loop and the message on the browser is, redirected too many times.
While, ideally what should have happened is, after getting validated, it should come back to /login route, and render dashboard page we have. but it is not happening.
you forget to install the keycloak middleware inside your application, add the lines given below in your code, it will resolve the issue:
app.use(keycloak.middleware({
logout:'/logout'}));
complete code sample given below:
var session = require('express-session');
var express = require('express');
var Keycloak = require('keycloak-connect');
var memoryStore = new session.MemoryStore();
var keycloak = new Keycloak({ store: memoryStore });
var app = express();
app.use(session({
secret: 'mySecret',
resave: false,
saveUninitialized: true,
store: memoryStore
}));
var keycloak = new Keycloak({
store: memoryStore
});
app.use(keycloak.middleware({
logout:'/logout'}));
app.use('/route1', keycloak.protect(), function(req, res){
console.log("AAAA")
res.json("AAAA")
})
// Server Start
app.listen(3000, function(){
console.log("Server Started")
})
In my project I call:
$ webpack-dev-server --history-api-fallback
And it starts an express server (I'm assuming) available on localhost:8080.
It works great except that I want to submit a form via POST into an iframe loading my app; localhost:8080 in development and something else in production.
I don't expect to do anything with that POST data in development, but in production, it needs to be POST.
When I try to use POST however, it cannot find POST /
Is there a configuration option or some other solution that will allow me to use the webpack-dev-server? (I really don't want to have to write my own server for this).
#cowCrazy had half of the story, but didn't show how to respond with the same response for GET in the case of POST, which is what I was looking for.
In the Webpack config, you do this:
module.exports = {
...,
devServer: {
setup(app) {
app.post('*', (req, res) => {
res.redirect(req.originalUrl);
});
},
}
}
This will just take the POST URL and redirect with the same URL, making it a GET request.
Instead of having a server error, it will redirect with GET.
What you are looking for is devServer. Bellow you can see my config for it. Under setup(app) you can add "almost" whatever you want:
module.exports = {
...,
devServer: {
inline: true,
port: 3000,
publicPath: '/',
setup(app){
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get("/get/some-data", function(req, res){
console.log(req);
res.send("GET res sent from webpack dev server")
})
app.post("/post/some-data", bodyParser.json(), function(req, res){
console.log(req.body);
res.send("POST res sent from webpack dev server")
})
}
}
}
EDIT:
I have pushed a minimalistic example to github if you wanna take a better look.
Check if it solves your problem by converting the POST request to GET request:
bypass: function (req, res, proxyOptions) {
const url = req.url;
req.method = 'GET';
if (url.indexOf('?') > -1) {
return url.replace('?', '.json?');
} else {
return url + '.json';
}
}
I was watching Steve Sanderson's NDC presentation on up-and-coming web features, and saw his caching example as a prime candidate for an application I am developing. I couldn't find the code, so I have typed it up off the Youtube video as well as I could.
Unfortunately it doesn't work in Chrome (which is also what he is using in the demo) It fails with Uncaught TypeError: fetch(...).then(...).timeout is not a function
at self.addEventListener.event.
I trawled through Steve's Github, and found no trace of this, nor could I find anything on the NDC Conference page
//inspiration:
// https://www.youtube.com/watch?v=MiLAE6HMr10
//self.importScripts('scripts/util.js');
console.log('Service Worker script running');
self.addEventListener('install', event => {
console.log('WORKER: installing');
const urlsToCache = ['/ServiceWorkerExperiment/', '/ServiceWorkerExperiment/scripts/page.js'];
caches.delete('mycache');
event.waitUntil(
caches.open('mycache')
.then(cache => cache.addAll(urlsToCache))
.then(_ => self.skipWaiting())
);
});
self.addEventListener('fetch', event => {
console.log(`WORKER: Intercepted request for ${event.request.url}`);
if (event.request.method !== 'GET') {
return;
}
event.respondWith(
fetch(event.request)
.then(networkResponse => {
console.log(`WORKER: Updating cached data for ${event.request.url}`);
var responseClone = networkResponse.clone();
caches.open('mycache').then(cache => cache.put(event.request, responseClone));
return networkResponse;
})
//if network fails or is too slow, return cached data
//reference for this code: https://youtu.be/MiLAE6HMr10?t=1003
.timeout(200)
.catch(_ => {
console.log(`WORKER: Serving ${event.request.url} from CACHE`);
return caches.match(event.request);
})
);
});
As far as I read the fetch() documentation, there is no timeout function, so my assumption is that the timeout function is added in the util.js which is never shown in the presentation... can anyone confirm this? and does anyone have an Idea about how this is implemented?
Future:
It's coming.
According to Jake Archibald's comment on whatwg/fetch the future syntax will be:
Using the abort syntax, you'll be able to do:
const controller = new AbortController();
const signal = controller.signal;
const fetchPromise = fetch(url, {signal});
// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetchPromise;
// …
If you only wanted to timeout the request, not the response, add:
clearTimeout(timeoutId);
// …
And from another comment:
Edge & Firefox are already implementing. Chrome will start shortly.
Now:
If you want to try the solution that works now, the most sensible way is to use this module.
It allows you to use syntax like:
return fetch('/path', {timeout: 500}).then(function() {
// successful fetch
}).catch(function(error) {
// network request failed / timeout
})
Good afternoon everyone.
I'm working on a school project to create an application using the MEAN stack, and I'm having issues with routing.
I'm using the login-and-register application found here as a base for my work : http://jasonwatmore.com/post/2015/12/09/mean-stack-user-registration-and-login-example-tutorial
Basically, I am unable to post data that I get from a form I created to my database.
If I get the creation part to work, then I'll be able to continue working on my project. Here is the code :
The Controller
(function () {
'use strict';
function Controller(UserService, NoteService, FlashService) {
var vm = this;
vm.note = null;
function createNote() {
NoteService.Create(vm.note, vm.user)
.then(function () {
FlashService.Success('Note created');
})
.catch(function (error) {
FlashService.Error(error);
});
}
vm.createNote = createNote;
function initController() {...}
initController();
}
angular.module('app').controller('Home.IndexController', Controller);
}());
And then we have the service I'm calling, NoteService
(function () {
'use strict';
function Service($http, $q) {
var service = {};
function Create(note, user) {
return $http.post('/api/notes', note).then(handleSuccess, handleError);
}
service.Create = Create;
return service;
}
angular
.module('app')
.factory('NoteService', Service);
}());
This is the $http.post function that doesn't work : /api/notes cannot be found (error 404 on browser console) I am sure my object note is getting at least to this request, because adding a console.log(note) just before returns what I want in the console.
On the server side, I have another controller for handling errors :
var noteService = require('services/notes.service');
//routes
router.post('/create', createNote);
module.exports = router;
function createNote(req, res) {
noteService.create(req.body)
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
the service on the server side to discuss with the data base :
var mongo = require('mongoskin');
var db = mongo.db(config.connectionString, { native_parser: true });
db.bind('notes');
var service = {};
service.create = create;
module.exports = service;
function create(noteParam, userParam) {...}
and my server.js file looks like this :
require('rootpath')();
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(session({ secret: config.secret, resave: false, saveUninitialized: true }));
// use JWT auth to secure the api
app.use('/api', expressJwt({ secret: config.secret }).unless({ path: ['/api/users/authenticate', '/api/users/register'] }));
// routes
app.use('/login', require('./controllers/login.controller'));
app.use('/register', require('./controllers/register.controller'));
app.use('/app', require('./controllers/app.controller'));
app.use('/api/users', require('./controllers/api/users.controller'));
app.use('/api/notes', require('./controllers/api/notes.controller'));
// make '/app' default route
app.get('/', function (req, res) {
return res.redirect('/app');
});
// start server
var server = app.listen(3000, function () {
console.log('Server listening at http://' + server.address().address + ':' + server.address().port);
});
I thought this line in the server.js file : app.use('/api/notes', require('./controllers/api/notes.controller'))
would permit my post request to send my note object to the server side, to '/api/notes') but I'm not quite sure how all this works together.
I am hoping anyone can help me, even though the code I gave was lengthful.
I am just beginning with MEAN and have no idea what I'm doing wrong.
Thanks in Advance for your answer.
Here is a problem. When I ran these code:
String responseText = null;
HttpRequest.getString(url).then((resp) {
responseText = resp;
print(responseText);
});
print(responseText);
In console:
{"meta":{"code":200},"data":{"username":"kevin","bio":"CEO \u0026 Co-founder of Instagram","website":"","profile_picture":"http:\/\/images.ak.instagram.com\/profiles\/profile_3_75sq_1325536697.jpg","full_name":"Kevin Systrom","counts":{"media":1349,"followed_by":1110365,"follows":555},"id":"3"}}
null
It running asynchronously. Is there JAVA way with synchronized method? That will be await while request is done?
I found only one tricky way to do it and its funny -- wait for three seconds:
handleTimeout() {
print(responseText);
}
const TIMEOUT = const Duration(seconds: 3);
new Timer(TIMEOUT, handleTimeout);
And of course it works with bugs. So any suggestions?
MattB way work well:
var req = new HttpRequest();
req.onLoad.listen((e) {
responseText = req.responseText;
print(responseText);
});
req.open('GET', url, async: false);
req.send();
First, I'm assuming you're using this as a client-side script and not server-side. Using HttpRequest.getString will strictly return a Future (async method).
If you absolutely must have a synchronous request, you can construct a new HttpRequest object and call the open method passing the named parameter: async: false
var req = new HttpRequest();
req.onLoad.listen((e) => print(req.responseText));
req.open('GET', url, async: false);
req.send();
However it is highly recommended that you use async methods for accessing network resources as a synchronous call like above will cause the script to block and can potentially make it appear as though your page/script has stopped responding on poor network connections.