IIS UrlRewrite Not Working on 404 Requests - iis

I am trying to remove the "Server" header from IIS 8.0. I have installed UrlRewrite and added the following code to my web.config:
<rewrite>
<outboundRules rewriteBeforeCache="true">
<rule name="Remove Server header">
<match serverVariable="RESPONSE_Server" pattern=".+" />
<action type="Rewrite" value="" />
</rule>
</outboundRules>
</rewrite>
However, when a request comes in that generates a 404, the "Server" header is still included.
Any suggestions on how to resolve this issue?
I am using Web API 2 running on Windows Server 2012 with IIS 8.

Add an owin middleware first in your pipeline:
public void Configuration(IAppBuilder app)
{
app.Use(async (ctx, next) =>
{
ctx.Response.OnSendingHeaders(state =>
{
var res = (OwinResponse)state;
res.Headers.Remove("Server");
}, ctx.Response);
await next();
});
//...
}

Related

HTTP ERROR 400.605. Deploying NodeJS app on IIS

I've got error during deploying my app to IIS Server. I use URL Rewrite and IISNode. I gave all permissions to IUSR and IIS_IUSRS, and I went throught a lot of errors, but I can't go through this one. I will be very grateful for your help.
I've got this error
My web.config file looks like:
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="src/app.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="app">
<match url="/*" />
<action type="Rewrite" url="src/app.js" />
</rule>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:8080/{R:1}" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<add segment="node_modules" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
My app.js file looks like:
const express = require('express');
const cors = require('cors');
const app = express();
app.get('/', (req, res, status)=>{
return res.status(200).json({
"message": "Hello world!"
});
});
app.use(cors());
app.use(express.json());
app.listen(8080, () => {
console.log('App listening on port 8080')
});
From the analysis of the error information, it can be determined that the problem is caused by the abnormal request of the ARR module, mainly because of the syntax error of the URL rewriting rule, which will cause this 400.605 error. It is recommended to use the exclusion method, first disable all ARR rules, and then gradually sort out the rules with grammar problems.
Here is the same question you can use as a reference: ARR The request cannot be routed because it has reached the Max-Forwards limit. The server may be self-referencing itself in request routing topology.

API working from Postman, but getting error when posting from Angular

I have a POST Im performing from Postman, which works perfect, but when Im posting through Angular, Im getting:
[Error] XMLHttpRequest cannot load (DOMAIN) due to access control
checks.
After checking several answers here and at Google, I came up with changing web.config and express to enable CORS.
The NODE application is hosted on IIS, and I already added the customHeaders to the web.config:
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
The Angular code is pretty straight forward:
let APIURL = sessionStorage.getItem('endPoint') + "outside/login";
let options = { headers: new HttpHeaders().set('Content-Type', 'application/json') };
let body: any = this.payLoad;
this.httpClient.post(APIURL, JSON.stringify(body), options).subscribe(
result => {
.....
.....
.....
})
I also added
app.options('*', cors())
to Express but still get this error.
This worked perfect while I was using the IP address and port 3000 on the remote server. Everything crashed when I set the domain thru IIS and setup the URL Rewrite.
I want to put special emphasis on this: It works PERFECT on Postman, but it crashes through the app (localhost, or at the web server).
Thanks.
UPDATE: When stopping PM2 and stopping the IIS website, of course Postman does not work, but Angular retrieves the same error, so I tend to thing the problem is at an Angular level (?).
Here's the rewrite rule at IIS
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:3000/{R:1}" />
</rule>
</rules>
</rewrite>
Add this to your js file where you require express. I assume you are requiring CORS. If not:
const cors = require('cors')
then
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
and get rid of the customHeaders at your web.config. You are setting the headers twice.
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>

Host NextJs to IIS

Good Day!
My colleague has a website node.js (next.js), his website works fine when we build and start thru console (npm run build and npm start).
We have hosted it in a Azure VM (Windows Server 2016 IIS, iisnode and urlrewrite installed), we created a pipeline and we are able to get the artifacts (".next" folder when we run the build) and deploy it to IIS however we still need a manual interaction to place the web.config. Below is the web.config
<!-- indicates that the hello.js file is a node.js application
to be handled by the iisnode module -->
<handlers>
<add name="iisnode" path="service-worker.js" verb="*" modules="iisnode" />
</handlers>
<!-- use URL rewriting to redirect the entire branch of the URL namespace
to hello.js node.js application; for example, the following URLs will
all be handled by hello.js:
http://localhost/node/express/myapp/foo
http://localhost/node/express/myapp/bar
-->
<rewrite>
<rules>
<rule name="AMS" 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>
But when we visit the website, it throws an error of 403 that need to supply the default page. (I'm lost here and not able to run his website thru IIS)
Note: His other website works fine (because it has a service-worker.js).
Anyone experience deploying the Next.JS to IIS? Thanks in Advance.
In the /public folder, create the following web.config to accept requests from /a/b/c and rewrite them to / where our NextJs code lives.
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="NextJs Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Just doing this should allow you to reload a page on a route like /products, but NextJs will render /, ie, the index page, because that's what our rewrite rule told it to deliver.
So, we need to create a body Component that takes a NextRouter as a prop then compare the window's url to the router's url. If they don't match, we need to change our client side route with router.push().
I'm using TypeScript so my body.tsx is
import * as React from 'react';
import { NextRouter } from 'next/router';
export default class Body extends React.Component<{router : NextRouter}>
{
componentDidMount()
{
if (window.location.pathname == this.props.router.pathname) return;
this.props.router.push(global.window.location.pathname);
}
render = () => this.props.children;
}
Then in _app.tsx, we simply need to wrap the main Component in our Body Component.
import { useRouter } from 'next/router'
import Head from 'next/head';
import Body from '../src/components/elements/body';
function MyApp({ Component, pageProps }) {
const router = useRouter();
return (
<>
<Head>
<title>NextJs on IIS</title>
</Head>
<Body router={router}>
<Component {...pageProps} />
</Body>
</>
)
}
export default MyApp
Run npm run build, and copy the /out folder to your IIS server.

Need to fix routing issue with Angular 2 running on an Azure App service

I have an angular 2 website that is based on the Angular 2 "Tour of Heroes" Quick Start.
It works fine when running locally. After fixing things to no longer use local node_modules (per the deployment steps from the quick start) and deploying to the Azure web app the app works fine if I start at the root URL ("/"). However, using Angular routing the URL changes (to "/home" for example) and if I do an F5 refresh of that URL, the app fails to load. When I do that I get a 404 with:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
I tried using a web.config as described here but that did not help. It definitely seems like it is an IIS issue where it tries to serve up a page instead of starting with index.html. My routes are defined in Angular and they work locally.
Can you try this web.config file
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS Routes" 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>
<caching enabled="true" enableKernelCache="true">
<profiles>
<add extension=".js" policy="DisableCache" kernelCachePolicy="DisableCache" />
</profiles>
</caching>
</system.webServer>
</configuration>
The web.config solution did not work for me at all. After a day or so of digging around and tearing my hair out, I came across this post which resolved the issue for me. It appears to be doing something similar in that for a 404 that isn't related to any /api/ request, serve up the root page, whereupon the Angular routing should kick in and serve up the correct view. As per the link above, in Startup.cs at the beginning of the void Configure() method, I inserted the following code:
app.Use(async (HttpContext context, Func<Task> next) =>
{
await next.Invoke();
if (context.Response.StatusCode == 404 && !context.Request.Path.Value.Contains("/api"))
{
context.Request.Path = new PathString("/");
await next.Invoke();
}
});
The only thing I've done differently is set the root url to '/' (my root razor page that's hosting the Angular app) instead of index.html in the example. The versions I'm using are .NET Core 2.2 and Angular 7.2.1.
Add this file in src/assets/routes.json
{
"routes": [
{
"route": "/*",
"serve": "/index.html",
"statusCode": 200
}
]
}
let me know if it workes ?
Not sure if it's too late, but here is what you need
app-routing.module.ts add useHash: true
modify your navigation to use #
compile your application: ng build --configuration production
upload your files to your static site

Serving static files from iisnode with URL Rewrite

I am using a Rewrite rule in my web.config file for a node app running under issnode to point to my server.js file. myapp/* points to server.js.
<rule name="myapp" enabled="true">
<match url="myapp/*" />
<action type="Rewrite" url="server.js" />
</rule>
This has been working great www.mywebsite.com/myapp/ would load a run my app. What I wanted was to have a redirect from the root of the website so www.mywebsite.com/ would run my app. So I changed my web.config file
<rule name="myapp" enabled="true">
<match url="/*" />
<action type="Rewrite" url="server.js" />
</rule>
So this is running the server.js and serving up a my a static html file, the only problem is referencing any external files from my html file (css, js, images etc) Just get 500s for every request. I am using this to serve static files
var libpath = require('path');
var _path = "."; <-- This seems to be the problem
var uri = url.parse(req.url).pathname;
var filename = libpath.join(_path, uri);
fs.readFile(filename, "binary", function (err, file) {
if (err) {
res.writeHead(500, {
"Content-Type": "text/plain"
});
res.write(err + "\n");
res.end();
return;
}
var type = mime.lookup(filename);
res.writeHead(200, {
"Content-Type": type
});
res.write(file, "binary");
res.end();
});
break;
So my question is how to point to root of my node app / server to serve up static files.
Thanks
Jono
The best way to serve static content in iisnode is to configure the URL rewriting module such that the IIS static file handler handles requests for static content rather than node.js. Having IIS serve static content has a large performance benefit over serving these files using any node.js mechanisms due to kernel level optimizations around caching and just not having to break into JavaScript code.
For a boilerplate web.config configuration that achieves this see https://github.com/tjanczuk/iisnode/issues/160#issuecomment-5606547
I had some issues using the suggested rule config, so I made some changes:
<system.webServer>
<handlers>
<clear />
<add name="iisnode" path="/index.js" verb="*" modules="iisnode" />
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
</handlers>
<rewrite>
<rules>
<rule name="static">
<action type="Rewrite" url="www{REQUEST_URI}" />
</rule>
<rule name="serve-static" stopProcessing="true">
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}" matchType="IsFile" />
<add input="{REQUEST_URI}" pattern="^/www/$" />
</conditions>
</rule>
<rule name="node">
<action type="Rewrite" url="index.js" />
</rule>
</rules>
</rewrite>
</system.webServer>
First rule prefixes all requests with www, my client directory.
Second rule stops processing if the file exists or if the root path is requested
Third rule rewrites anything else to the name of my backend Node script so that it can be picked up by the iisnode handler.
Note the iisnode handler path is set to /index.js which seems to eliminate conflicts with client files of the same name.

Resources