I have a react UI application and a .NET API server.
The react app is running locally on: http://localhost:8082/myapp
The API app is running locally on IIS on: http://foo.local.bar.com/myappapi
I want them to communicate. Since they are running on different local domains, I needed a proxy to avoid CORS issue. On my react app, I put this code on my config.development.js
file:
devServer: {
logLevel: 'debug',
proxy: {
'/myappapi/api/*': {
target: 'http://foo.local.bar.com/',
headers: {
Cookie: ".MyCookie=12345"
},
logLevel: 'debug',
secure: false,
changeOrigin: true,
withCredentials: true
}
},
},
Well, it works great with GET method and I indeed get data from the API server to the UI.
The problem is with POST/PUT/DELETE methods that I want to pass data - it doesn't work and I get Gateway error after a while. I know I pass the right object because it works great on production environment, the problem is only on proxy mode (locally).
Things That I've found out until now:
- As I said, GET method works great (the data is in the URL, not in the body) so the proxy is defined correctly.
- a POST method without parameters works fine too.
- a POST method with parameters works fine without the proxy (Postman to the original URL in foo.local.bar, or in production mode).
This is the code in the server:
[Route("api/mycontroller/v1")]
[ApiController]
public class MyController : ControllerBase
{
private readonly ILogger logger;
private readonly IMyService myService;
/// Constructor
public MyController (IMyService myService) // When I send the POST method, I hit the breakpoint here
{
this.myService = myService;
logger = LogManager.GetCurrentClassLogger();
}
[HttpPost]
[Route("PostSomething1")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult> AddAsync(MyObjRequest myRequest)
{
// I never get here on proxy mode
}
[HttpPost]
[Route("PostSomething2")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult> AddAsync2()
{
// This one works fine - but I can't get data from UI so it doesn't help me much
}
}
CodePudding user response:
Well, after digging the code I've found out that our system is using HPM (httpProxyMiddleware) which has a bug in early versions (search Google for "fixRequestBody"). Since It's in our inner packages I couldn't upgrade the package so I copied the solution from GitHub to my project and matched it to JS instead of TS.
devServer: {
logLevel: 'debug',
proxy: {
'/myappapi/api/*': {
target: 'http://foo.local.bar.com/',
headers: {
Cookie: ".MyCookie=12345"
},
logLevel: 'debug',
secure: false,
changeOrigin: true,
withCredentials: true,
onProxyReq: fixRequestBody, // Here is the solution!!!
}
},
And the function is -
const queryString = require('queryString');
function fixRequestBody(proxyReq,req){
const requestBody = req?.body;
if (!requestBody || !Object.keys(requestBody).length) {
return;
}
const contentType = proxyReq.getHeader('Content-Type');
const writeBody = (bodyData) => {
// deepcode ignore ContentLengthInCode: bodyParser fix
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
proxyReq.write(bodyData);
};
if (contentType && contentType.includes('application/json')) {
writeBody(JSON.stringify(requestBody));
}
if (contentType === 'application/x-www-form-urlencoded') {
writeBody(queryString.stringify(requestBody));
}
}