iisnode gives 'Bad Request' for post method - node.js

I have developed nodejs express app. It is working fine when running on node server. But after hosting on iis server it always gives 'Bad Request' as response.
Get calls are working fine.
following is my web.conf file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^server.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="server.js"/>
</rule>
</rules>
</rewrite>
<iisnode
nodeProcessCommandLine="C:\Program Files\nodejs\node.exe"
nodeProcessCountPerApplication="1"
maxConcurrentRequestsPerProcess="1024"
maxNamedPipeConnectionRetry="100"
namedPipeConnectionRetryDelay="250"
maxNamedPipeConnectionPoolSize="512"
maxNamedPipePooledConnectionAge="30000"
asyncCompletionThreadCount="0"
initialRequestBufferSize="4096"
maxRequestBufferSize="65536"
watchedFiles="*.js;iisnode.yml"
uncFileChangesPollingInterval="5000"
gracefulShutdownTimeout="60000"
loggingEnabled="false"
logDirectory="iisnode"
debuggingEnabled="true"
debugHeaderEnabled="false"
debuggerPortRange="5058-6058"
debuggerPathSegment="debug"
maxLogFileSizeInKB="128"
maxTotalLogFileSizeInKB="1024"
maxLogFiles="20"
devErrorsEnabled="true"
flushResponse="false"
enableXFF="false"
promoteServerVars=""
configOverrides="iisnode.yml"
/>
<modules>
<remove name="WebDAVModule"/>
</modules>
</system.webServer>
</configuration>
server.js file as follows
'use strict';
// Module dependencies.
var express = require('express'),
path = require('path'),
fs = require('fs'),
methodOverride = require('method-override'),
morgan = require('morgan'),
bodyParser = require('body-parser');
var app = module.exports = exports.app = express();
app.locals.siteName = "IOS IBE";
app.use(express.static(__dirname + '/public'));
app.get('/*', function (req, res) {
res.sendFile(__dirname + '/public/index.html');
});
app.use(methodOverride());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
// Start server
var port = process.env.PORT;
app.listen(port, function () {
console.log('DP Admin server listening on port %d in %s mode', port, app.get('env'));
});

I could fixed this issue by adding
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
to web.config .
Hope this will help to any one else.

Related

Angular 9 universal deploy to azure with web.config file

have created an Asp.NET Core Web Application with Angular 9. I have added Angular Universal to my application. Now I need to publish my application into the Azure app service.
I have used the following command to build an application,
npm run build:ssr
After building angular universal application it will give two folder structures under the dist folder.
dist/{app-name}/browser
dist/{app-name}/server
It's working fine locally. Now I need to publish the application in the Azure app service. So far I have searched a lot of things and integrated them. But unfortunately, I did not find any solution to work for the last couple of days.
Here is my web.config file
<?xml version="1.0" encoding="utf-8"?>
<configuration>`
<system.webServer>
<webSocket enabled="false"/>
<handlers>
<add name="iisnode" path="index.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^/index.js\/debug[\/]?"/>
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="index.js"/>
</rule>
<rule name="DigitalTalksAngulartest" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/digitaltalkstest/" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough"/>
</system.webServer>
</configuration>
server.ts file
import 'zone.js/dist/zone-node';
import { ngExpressEngine } from '#nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '#angular/common';
import { existsSync } from 'fs';
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express();
let distFolder = join(process.cwd(),'dist/#abb/customer-platform/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
const MockBrowser = require('mock-browser').mocks.MockBrowser;
const mock = new MockBrowser();
const win = mock.getWindow();
global['window'] = win;
global['document'] = mock.getDocument();
global['location'] = mock.getLocation();
global['navigator'] = mock.getNavigator();
global['history'] = mock.getHistory();
global['localStorage'] = mock.getLocalStorage();
global['sessionStorage'] = mock.getSessionStorage();
global['object'] = win.object;
global['HTMLElement'] = win.HTMLElement;
global['Event'] = win.Event;
global['Event']['prototype'] = win.Event.prototype;
global.Buffer = global.Buffer || require('buffer').Buffer;
global.btoa = function (str) {
return Buffer.from(str, 'binary').toString('base64');
};
global.atob = function (b64Encoded) {
return Buffer.from(b64Encoded, 'base64').toString('binary');
};
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
currently, the normal angular application resides in site/wwwroot/projec-name
Inside this path, all my build contents reside. Build content consists of web.config, index.html, and all other files.
Any help is appreciated.

HTTP Error 405 Method Not Allowed from AZURE

Looking for some assistance with this error.
After hosting my Node.js & Angular project at azure I'm getting that error on POST request:
Http failure response for https://https://green-market.azurewebsites.net/api/auth/login: 405 Method Not Allowed
This is my web.config file:
<?xml version="1.0"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
<handlers>
<remove name="iisnode" />
<add name="iisnode" path="app.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="Angular Routing" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile"
negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory"
negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
<staticContent>
<mimeMap fileExtension="woff" mimeType="application/font-woff" />
<mimeMap fileExtension="json" mimeType="application/json" />
</staticContent>
</system.webServer>
</configuration>
And this is my app.js file from node.js server:
let originUrl;
if (process.env.PORT) {
global.config = require("./config-prod");
originUrl = "https://green-market.azurewebsites.net";
}
else {
global.config = require("./config-dev");
originUrl = "http://localhost:4200";
}
require("./data-access-layer/dal");
const express = require("express");
const session = require("express-session");
const path = require("path");
const cors = require("cors");
const productsController = require("./controllers/products-controller");
const authController = require("./controllers/auth-controller");
const shoppingCartsController = require("./controllers/shopping-carts-controller");
const ordersController = require("./controllers/orders-controller");
const citiesController = require("./controllers/cities-controller");
const server = express();
const fileUpload = require("express-fileupload");
const { request, response } = require("express");
const { url } = require("inspector");
server.use(fileUpload());
server.use(express.json());
server.use(express.static(path.join(__dirname, "./_front-end")));
server.use(cors({
origin: originUrl,
credentials: true
}));
server.use(session({
name: "OnlineMarketSession",
secret: "itsASecret",
resave: true,
saveUninitialized: false,
}));
server.use("/api/products", productsController);
server.use("/api/shopping-carts", shoppingCartsController);
server.use("/api/orders", ordersController);
server.use("/api/auth", authController);
server.use("/api/cities", citiesController);
// Any other route - return index.html as we are SPA:
server.use("*", (request, response) => {
response.sendFile(path.join(__dirname, "./_front-end/index.html"));
});
const port = process.env.PORT || 3000;
server.listen(port, () => console.log(`Listening on port ${port}`));
Thank you!

How to configure Azure web app to host Nextjs app

I'm trying to host a simple Nextjs application on Azure WebApp, i have tried to follow several online tutorials to configure it but none managed to help me.
I'm using the SSR configuration of the Nextjs and have only created two components to test it on the Azure hosting.
Right now i'm stuck at the server configuration for Node, i have tried place a web.config file that i saw on an example but it seems that my request isn't event reaching the application server.
This is my web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="app/server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="API">
<match url="^api(.*)$" />
<conditions logicalGrouping="MatchAll">
<add input="{SCRIPT_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{SCRIPT_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="api/index.php" appendQueryString="true" />
</rule>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^app/server.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="app/server.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
This is my server.js
const express = require('express')
const next = require('next')
const nextConfig = require('../next.config')
const port = process.env.PORT || 8080
const dev = process.env.NODE_ENV !== 'production'
const app = next({
dev: dev,
dir: './app',
conf: nextConfig
})
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.get('/home', (req, res) => {
return app.render(req, res, '/home', req.query)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})

Route error in Angular 6/Express

I'm developping a nodeJS/Angular 6/Express app.
There's only 1 route in express for the "back-end" and many routes for angular.
I have no problems to run that locally but when I try to deploy it on Azure, Angular routes works fine but not back-end routes (which redirect me to the root url).
I think Angular is taking priority on back-end routes.
Here are some files :
server.js :
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const fetch = require('node-fetch');
const publicweb = './dist/forms';
const app = express();
app.use(express.static(publicweb));
app.use('/api/test', (req, res) => {
res.send("test");
});
app.get('*', (req, res) => {
res.sendFile('index.html', { root: publicweb });
});
const port = '1337';
app.listen(port, () => console.log(`API running on localhost:${port}`));
web.config :
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="Express.js URIs">
<match url="api/*" />
<action type="Rewrite" url="server.js" />
</rule>
<rule name="Angular" stopProcessing="true">
<match url="/*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory"
negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
package.json :
"start" : "node src/server.js"
app-routing.module.ts :
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { RetailComponent } from './retail/form/retail.component';
const routes: Routes = [
{
path: '',
redirectTo: '/',
pathMatch: 'full'
},
{
path: 'retail',
component: RetailComponent
}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
When I deploy that app on Azure, and I try to access /api/test
My build definition in Azure
Many thanks for your answer!
I think all your get request are mapping to this piece of code
app.get('*', (req, res) => {
enter code here`res.sendFile('index.html', { root: publicweb });
});
that is why you are getting index.html in your queries to your server.
And app.use() is to be used for applying middleware so after middleware work is over the app.get() method gets executed and so you get index.html

web.config with angular universal

I want to run angular 4 univeral in Azure Web. I deployed the code, but I have some troubles with web.config (i think so).
The server.js located in dist folder, so I set path in web.config "dist/server.js", but when server.js runs it gives an error:
ENOENT: no such file or directory, open 'D:\home\site\wwwroot\dist\dist\browser\index.html'
If I remove the "dist" from path it will 404. And if I remove "dist" from
const DIST_FOLDER = join(process.cwd(), 'dist'); in server.js
it will give me an error:
ENOENT: no such file or directory, open 'D:\home\site\wwwroot\browser\index.html'
Or double dist, or no dist at all.
The web.config looks like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="dist/server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^dist/server.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="dist/server.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
The server.js code:
const PORT = process.env.PORT || 8080;
const DIST_FOLDER = join(process.cwd(), 'dist');
const app = express();
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
const { AppServerModuleNgFactory } = require('main.server');
app.engine('html', (_, options, callback) => {
const opts = { document: template, url: options.req.url };
renderModuleFactory(AppServerModuleNgFactory, opts)
.then(html => callback(null, html));
});
app.set('view engine', 'html');
app.set('views', 'src');
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
app.get('*', (req, res) => {
res.render('index', { req });
});
app.listen(PORT, () => {
console.log(`listening on http://localhost:${PORT}!`);
});
I figured out, instead of process.cwd(), I should use __dirname.
Your server.js is located in "dist" folder. So, please change the following line
const DIST_FOLDER = join(process.cwd(), 'dist');
to
const DIST_FOLDER = process.cwd();

Resources