I'm fairly new to NodeJS and I'm trying to implement HTTPS request from NodeJS (backend) directly to a middleware api hosted in IISNode with a GoDaddy certificate. I have another repo for my view (frontend) and all the calls to the middleware api through the browser are working with the GoDaddy certificate. The calls work fine with HTTP using Axios. When making the call to the middleware api with HTTPS from the NodeJS backend I'm getting:
Error: self signed certificate
at TLSSocket.onConnectSecure (_tls_wrap.js:1058:34)
at TLSSocket.emit (events.js:198:13)
at TLSSocket.EventEmitter.emit (domain.js:448:20)
at TLSSocket._finishInit (_tls_wrap.js:636:8)
It's really weird that the frontend repo communicates with no issue to the middleware via the browser but the NodeJS backend calls will not. I have tried using Axios in the backend with no luck and cert errors. I switched to HTTPS and the GET calls are working, but POST calls give me the error above.
I have read tons of posts and examples regarding self-signed certs but I'm using a cert that is generated from GoDaddy. Here are some code snippets I've tried:
Axios:
const SSLAgent = new https.Agent({
rejectUnauthorized: true,
passphrase: process.env.PASSPHRASE,
pfx: fs.readFileSync(path.join(__dirname, "../../") + process.env.PFX),
ca: fs.readFileSync(path.join(__dirname, "../../") + process.env.CRT_BUNDLE)
});
const fetchData = () => axios.get(`${process.env.MIDDLE_WARE_URL}/something`, {
headers: {
Authorization: `Bearer ${token}`
},
httpsAgent: SSLAgent
});
const uploadData = () => {
const form = new FormData();
form.append("data", fs.createReadStream(dataPath));
return axios.post(`${process.env.MIDDLE_WARE_URL}/data`, form, {
headers: {
...form.getHeaders(),
Authorization: `Bearer ${token}`
},
httpsAgent: SSLAgent
});
};
const fetchItemImage = (ItemID: number) => axios.get(`${process.env.MIDDLE_WARE_URL}/item/${ItemID}/image.png`, {
responseType: "arraybuffer",
headers: {Authorization: `Bearer ${token}`},
httpsAgent: new https.Agent({pfx: fs.readFileSync(path.join(__dirname, "../../") + process.env.PFX), passphrase: process.env.PASSPHRASE}), ca: fs.readFileSync(path.join(__dirname, "../../") + process.env.CRT_BUNDLE)
});
HTTPS:
const SSLAgent = {
rejectUnauthorized: true,
passphrase: process.env.PASSPHRASE,
pfx: fs.readFileSync(path.join(__dirname, "../../") + process.env.PFX),
ca: fs.readFileSync(path.join(__dirname, "../../") + process.env.CRT_BUNDLE)
};
const middleServer = express;
const middle = express.Router();
https.createServer(SSLAgent, middleServer).listen(443);
let data;
const dataOptions = {
headers: {
"Authorization": `Bearer ${token}`
}
};
const fetchData = () => middle.get("/data", (req, res) => {
console.log("The req is: ", req);
if (res.statusCode === 200) {
console.log("The Fetch Data Res: ", res);
data = res;
}
data = [];
});
const uploadStuff = () => {
const form = new FormData();
form.append("Stuff", fs.createReadStream(stuffPath));
const stuffOptions = {
headers: {
...form.getHeaders(),
"Authorization": `Bearer ${token}`
},
form
};
return middle.post("/stuff", (req, res) => {
req.params(stuffOptions);
res.on("data", () => {
console.log("The post response is: ", res);
});
res.on("error", (error) => {
console.log("The post error is: ", error);
});
});
};
Also, here is my IIS web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="iis.js" verb="*" modules="iisnode" />
<add name="iisnode-socketio" path="iis.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="my_middleware">
<match url="/*" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" redirectType="Found" url="https://{HTTPS_HOST}/{R:1}" />
</rule>
<!-- Don't interfere with requests for logs -->
<rule name="LogFile" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^[a-zA-Z0-9_\-]+\.js\.logs\/\d+\.txt$" />
</rule>
<!-- Don't interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^app.js\/debug[\/]?" />
</rule>
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}" />
</rule>
<!-- All other URLs are mapped to the Node.js application entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True" />
</conditions>
<action type="Rewrite" url="iis.js" logRewrittenUrl="true" />
</rule>
<rule name="SocketIO" patternSyntax="ECMAScript">
<match url="socket.io.+" />
<action type="Rewrite" url="iis.js" />
</rule>
</rules>
</rewrite>
<webSocket enabled="false" />
<iisnode debugHeaderEnabled="true" promoteServerVars="AUTH_USER,AUTH_TYPE,LOGON_USER" />
<security>
<authorization>
<remove users="*" roles="" verbs="" />
<add accessType="Allow" users="?" verbs="OPTIONS" />
<add accessType="Allow" users="*" roles="" />
</authorization>
<requestFiltering>
<requestLimits maxAllowedContentLength="4294967295" />
</requestFiltering>
</security>
<defaultDocument>
<files>
<add value="iis.js" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
Related
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.
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!
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}`)
})
})
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
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();