Well currently I am disallowing all file uploads to routes by setting up the server like:
const upload = multer();
const server = express();
module.exports = () => {
// ...
server.use(logger('dev'));
server.use(express.json());
server.use(express.urlencoded({ extended: false }));
server.use(express.raw());
server.use(cookieParser());
server.use(express.static(path.join(projectRoot, 'public')));
server.set('trust proxy', 1);
server.use(upload.none());
server.use('/', router);
// ...
}
Which correctly blocks all files. Now I wish to allow uploading files only in the POST request to /test:
import * as express from "express";
import multer from "multer";
const upload = multer({storage: multer.memoryStorage()});
const router = express.Router();
router.post('/test', upload.single('pdf'), function(req, res, next) {
const r = 'respond with a test - POST';
res.send(r);
});
However when I try to use this in postman I get the error "multerError", "LIMIT_UNEXPECTED_FILE" for the field 'pdf'. I notice that if I remove the line server.use(multer.none()) it works, but then I can upload files to any place anyways, not exactly what I like?
Nothing will be uploaded to your server unless you specify a multer middleware on the entire server, on a route, or on a particular path. So you can safely remove the server.use(upload.none());.
The middleware will then not try to consume the payload of the incoming request. How much load the receiving (without consumption) of the payload causes on the server, I don't know, but you could theoretically destroy the connection whenever the client tries to submit a payload:
req.on("data", function() {
req.destroy();
});
But perhaps the creation of new connection afterwards causes more load on the server overall.
Related
I'm on Nuxt 2.15.8 and trying to build an offline app with electron.js and prisma+sqlite for local DB.
In nuxt to hit a local endpoint there is a common way of using serverMiddleware and express like this:
// api.js that will be added to nuxt.config.js file as serverMiddleware
import express from 'express'
const app = express()
app.use(express.json())
export default {
path: '/api',
handler: app
}
which send endpoints beginning with api/ through app handler which I can use to access my BD (the common way to access sqlite3 DB is the same)
// added to api.js
import { PrismaClient } from '../../resources/prisma/client'
const prisma = new PrismaClient()
app.get(`/user/info`, async (req, res) => {
const result = await prisma.user.findUnique({
where: {
id: 1,
},
})
console.console.log(res);
res.json(result)
})
this will work fine on nuxt, also fine on nuxt-electron dev mode. but on built exe file serverMiddleware won't be called. So as it has be done by others (nuxt-electron accessing offline local DB) there must be a way to define endpoints on client side. any idea??
Updated:
as I changed my Nuxt-Electron boilerplate I could access serverMiddleware in exe file but it wont hit the endpoints yet!
I want to have a route for my static files:
// server.js
app.use('/', require('./routes/ui/templates'));
The thing is that I cannot change the content-type from html->xhtml. Here's my route:
const express = require('express');
const router = express.Router();
// Path configs
const pathRoot = __dirname
const pathPublic = pathRoot + "/../../public/"
router.use('/', express.static(pathPublic));
router.get('/', (req, res) => {
console.log(pathPublic)
res.sendFile('index.html', {root: pathRoot});
})
router.use((req, res, next) => {
res.type('application/xhtml+xml');
next();
})
module.exports = router;
Note that for some reason, if I don't add the router.use(...)
my index file is not served at all. From what I understand, the middleware I've
written should be last as I am trying to capture the response and modify it.
Please correct me if I am wrong.
If you want to manage the Content-Type for specific types of files sent by express.static(), you can use the setHeaders option like this:
app.use(express.static(path.join(__dirname, "public"), {
setHeaders: function(res, path, stat) {
// if file is a .xml file, then set content-type
if (path.endsWith(".xml")) {
res.setHeader("Content-Type", "application/xhtml+xml");
}
}
}));
Some other things you may also be asking about:
Once your express.static() route matches a file, no further routing is done. The response is sent and none of the route handlers that follow will be called. So, you can't impact the content-type elsewhere with later routes.
If the request route path is /, then express.static() will look for an index.html file in the pathPublic you're passing it. If it finds it, it will send that and no further routing will happen.
res.type() does not do what you seem to be trying to use it for. You pass it a file extension and it sets the content-type according to a mime lookup for that file extension. As you can see in my code example above, you can set the content type yourself with res.setHeader("Content-Type", "application/xhtml+xml").
Try res.setHeader('content-type', 'application/xhtml+xml');
I am trying to implement some middleware in Express that should be called for all routes. This middleware should alter the request object.
I've tried several things already but seem to keep having the same issue. Soon as the middleware is left it looks like the request object is changed back to it's original state.
Currently my code resembles (I simplified it with a minimalistic example):
route.js:
const express = require('express');
const router = express.Router();
router.get('/getMe', (req, res) => {
// return the desired data.
// I expect req.params.myString to exist here but it does not.
});
module.exports = router;
index.js:
const express = require('express');
const router = express.Router();
router.use('/', require('./route'));
module.exports = router;
app.js:
const express = require('express');
const app = express();
const routes = require('./index');
app.use((req, res, next) => {
// Adding req.params.myString to the request object.
if (req.params.myString === undefined) req.params.myString = 'hello world';
next();
});
app.use('/api', routes);
As you can see I left out some of the code to keep it more readable. This is the code that gets the response and sets up the server.
Again, I am expecting that req.params.myString becomes available in the endpoint. Does anyone see what I am doing wrong?
In express docs ( http://expressjs.com/en/api.html#req.params ) it says:
If you need to make changes to a key in req.params, use the app.param
handler. Changes are applicable only to parameters already defined in
the route path.
So you need to check app.param handler.
http://expressjs.com/en/4x/api.html#app.param
You should app.set("myString", "hello World") inside your app.js and then you can access the field in your route.js/index.js scripts by using req.app.get("myString"). Or this should work too, set it like app.myString = "Hello world" and access it like req.app.myString.
Here are my routes:
app.get('/signUp', routes.signUp);
app.post('/signUp' , routes.signUp);
Here is my separate file for routes.
exports.signUp = function(req, res) {
res.render('signUp');
};
The second block of code is behaviour I want in response to a get request.
How do I respond to a post request? I have already tied up the signUp function with behaviour that responds to get. Do I bundle up the post behaviour in the same function and render the sign up page again? Suppose I simply want to render the view, I don't want the post behaviour to execute in that case so it would be strange to bundle those together.
I believe the express router module should resolve this for you.
route file -
var express = require('express');
var router = express.Router();
router.route("/")
.get(function (req, res) {
res.render('signUp');
})
.post(function (req, res) {
//do something else
})
module.exports = router
index.js/app.js/server.js/whatever you call it.
//..
signUp = require("./routes/signup.js"); //or wherever this is
//...
app.use("/signUp", signUp);
//..
quick question regarding using React-Router. I'm having trouble getting my server to handle pushState (if this is the correct term). Originally, I was using a module called connect-history-api-fallback, which was a middleware that enabled me to only server up static files form my dist directory. Visiting the client www.example.com obviously worked and I could navigate throughout the site, additionally, refreshing at any route like www.example.com/about - could also work.
However, I recently added one simple API endpoint on my Express server for the React app/client to ping. The problem now is that while I can get the initial page load to work (and thus the /api/news call to work, to fetch data from a remote service), I can no longer do a refresh on any other routes. For example, now going to www.example.com/about will result in a failed GET request for /about. How can I remediate this? Really appreciate the help! PS - not sure if it matters, but I'm considering implementing Server Side Rendering later on.
import express from 'express';
import historyApiFallback from 'connect-history-api-fallback';
import config from '../config';
import chalk from 'chalk';
import fetch from 'node-fetch';
import path from 'path';
const app = express();
// FIXME: Unsure whether or not this can be used.
// app.use(historyApiFallback({
// verbose : true
// }));
//// DEVELOPMENT MODE ONLY - USING EXPRESS + HMR ////
/* Enable webpack middleware for hot module reloading */
if (config.get('globals').__DEV__) {
const webpack = require('webpack');
const webpackConfig = require('../build/webpack/development_hot');
const compiler = webpack(webpackConfig);
app.use(require('./middleware/webpack-dev')({
compiler,
publicPath : webpackConfig.output.publicPath
}));
app.use(require('./middleware/webpack-hmr')({ compiler }));
}
//// PRODUCTION MODE ONLY - EXPRESS SERVER /////
if (config.get('globals').__PROD__) {
app.use(express.static(__dirname + '/dist'));
}
//// API ENDPOINTS FOR ALL ENV ////
app.get('/api/news', function (req, res) {
fetch('http://app-service:5000/news')
.then( response => response.json() )
.then( data => res.send(data) )
.catch( () => res.sendStatus(404) );
});
// Wildcard route set up to capture other requests (currently getting undexpected token '<' error in console)
app.get('*', function (req, res) {
res.sendFile(path.resolve(__dirname, '../dist', 'index.html'));
});
export default app;
Express works by implementing a series of middleware that you "plug in" in order via .use. The cool thing is your routes are also just middlware — so you can separate them out, have them before your history fallback, and then only requests that make it past your routes (e.g., didn't match any routes) will hit the fallback.
Try something like the following:
const app = express();
// ...
var routes = exprss.Router();
routes.get('/api/news', function (req, res) {
fetch('http://app-service:5000/news')
.then( response => response.json() )
.then( data => res.send(data) )
.catch( () => res.sendStatus(404) );
});
app.use(routes);
app.use(historyApiFallback({
verbose : true
}));