Azure / iisnode

Hosting node.js applications in IIS on Windows
Other
661 stars 101 forks source link

POST requests return 500 when using IIS/iisnode in Azure App Service, but work fine when developing locally WITHOUT IIS/iisnode #99

Open stevieray8450 opened 4 years ago

stevieray8450 commented 4 years ago

Repro steps:

Issue: When my app -- accessed at https://sjb8450-multitest.azurewebsites.net/ -- submits a POST request to https://sjb8450-multitest.azurewebsites.net/api, I get 500s. I'm fairly certain this is due to some IIS/iisnode problem, as it works absolutely fine locally.

Note that my GET /api endpoint is working fine.

Relevant code: /api is registered and handled in app.js, the root of my application:

const express = require('express');
const app = express();
const port = process.env.PORT || 80;
const indexRouter = require('./routes/index');
const apiRouter = require('./routes/api');
const path = require('path');
const envJson = require('dotenv-json');

envJson();
app.use(express.json());
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/api', apiRouter);

app.listen(port);

the route handler (api.js):

var express = require('express');
var router = express.Router();
var tableStorage = require('../tableClient');
var azure = require('azure-storage');
var entGen = azure.TableUtilities.entityGenerator;
var moment = require('moment');

router.get('/', function (req, res, next) {
    res.send('okee dokee'); **// NOTE: THIS WORKS!**
});

router.post('/', function (req, res, next) {
    const dateOfVisit = req.body.dateOfVisit;
    const momentDateOfVisit = moment(dateOfVisit);
    const location = req.body.location;
    const service = tableStorage();

    const entity = {
        PartitionKey: entGen.String(momentDateOfVisit.month().toString() + '.' + momentDateOfVisit.year().toString()),
        RowKey: entGen.String(dateOfVisit.toString()),
        DateOfVisit: entGen.DateTime(dateOfVisit),
        Location: entGen.String(location)
    };

    service.insertOrReplaceEntity('workoutLogs', entity, (error, result, response) => {
        console.log('response: ', response);

        if (!error && response.isSuccessful) {
            res.send('workout recorded!');
        } else {
            res.send(500, error);
        }
    });
});

module.exports = router;

and web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="iisnode" path="app.js" verb="*" modules="iisnode" />
    </handlers>

    <rewrite>
      <rules>
        <!-- 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" patternSyntax="Wildcard">
          <action type="Rewrite" url="public/{R:0}" logRewrittenUrl="true"/>
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
          </conditions>
          <match url="*.*"/>
        </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="app.js"/>
        </rule>

        <rule name="SocketIO" patternSyntax="ECMAScript">
          <match url="socket.io.+"/>
          <action type="Rewrite" url="app.js"/>
        </rule>
      </rules>
    </rewrite>

    <!-- <iisnode promoteServerVars="LOGON_USER" /> -->
    <httpErrors existingResponse="PassThrough" />
  </system.webServer>
</configuration>
recepdmr commented 1 year ago

@stevieray8450 Did you solve this problem?