chimurai / http-proxy-middleware

:zap: The one-liner node.js http-proxy middleware for connect, express, next.js and more
MIT License
10.77k stars 852 forks source link

Proxy doesn't work on external API #360

Closed zzulanas closed 3 years ago

zzulanas commented 5 years ago

Is this a question?

So I've got a question about my setup (yes I've looked on StackOverflow and through the other issues). Currently I've got a react app I bootstrapped with create-react-app. When in development, I use the webpack dev server proxy to proxy my API requests to an external API so I don't get hit with CORS errors. This works great locally, but when I build my site for production, I get hit with the CORS errors again.

(index):1 Access to XMLHttpRequest at 'https://e2esm-sandbox.com/api/now/table/sys_user?sysparm_limit=5&sysparm_query=employee_number=117' (redirected from 'http://localhost:8080/api/now/table/sys_user?sysparm_limit=5&sysparm_query=employee_number=117') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

In production our site is hosted on an Nginx instance, but I'm trying to mimic the webpack proxy behavior to avoid the CORS errors and am trying to use a simple Node.js server with this library.

According to the person who manages the API (not me, someone else in our company), he said that in order to avoid these I need to get it hosted on the same internal domain (website.company.com) which I have, but I still get CORS errors. I talked with someone else on his team and he said I needed to have a server make the requests, not the client (I'm pretty new at this whole web dev thing, I'm just an intern).

I currently have the react site making requests with axios that look like this

 axios.get(`/api/now/table/sys_user?sysparm_limit=5&sysparm_query=employee_number=${WWID}`,
        headers: { 
          'Access-Control-Allow-Origin' : '*',
          'Access-Control-Allow-Methods' : 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
        })

and this is how the server.js looks like:

const express = require('express');
const proxy = require('http-proxy-middleware');
const path = require('path');

const app = express();

app.use(
    '/api',
    proxy({
        target: 'http://e2esm-sandbox.com',
        changeOrigin: true
    })
);

app.use(express.static(path.join(__dirname, '/build')));

app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname+'/build/index.html'))
    console.log(__dirname+'/build/index.html')
});

app.listen(8080, () => {
    console.log('Server is running on localhost:8080')
});

But whenever I try and make a request through the page, I still get a CORS error.

I'm not sure how I can get my expected behavior of the webpack dev server on my production server.

Steps to reproduce

  1. create a new react app
  2. find an external API to use
  3. make a call to the API through the proxy with the library targeting it in the app such as I have
  4. build the site to production, run the node server, and attempt to call the endpoint
  5. see if there are still CORS errors or not

Expected behavior

I expected it to behave such as the webpack-dev-server does with its proxy.

Actual behavior

It doesn't proxy the request and still runs in to CORS errors.

Setup

So the configuration we have in our server.js file looks like this:

const express = require('express');
const proxy = require('http-proxy-middleware');
const path = require('path');

const app = express();

app.use(
    '/api',
    proxy({
        target: 'http://e2esm-sandbox.intel.com',
        changeOrigin: true
    })
);

app.use(express.static(path.join(__dirname, '/build')));

app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname+'/build/index.html'))
    console.log(__dirname+'/build/index.html')
});

app.listen(8080, () => {
    console.log('Server is running on localhost:3000')
});

client info

Windows

target server info

Externally hosted server on the same network, uses the ServiceNow API.

mxsxs2 commented 5 years ago

Shouldn't these headers be set on your external API endpoint rather than on the request?

'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'GET,PUT,POST,DELETE,PATCH,OPTIONS'

That if your CORS error comes from http://e2esm-sandbox.intel.com.

If you call your Express server from an other domain, then you can use cors

Theoretically if you have this setup (as you said) React->proxy->api Then between react and proxy you should not get a CORS error. Between proxy and api you should get the CORS error if they are on separate domains. In this case you need the headers set on the API to white list your proxy's domain. Using Allow-Origin: * is not recommended, unless it is a private network.

This is not an issue with the middleware.

chimurai commented 5 years ago

(index):1 Access to XMLHttpRequest at 'https://e2esm-sandbox.com/api/now/table/sys_user?sysparm_limit=5&sysparm_query=employee_number=117' (redirected from 'http://localhost:8080/api/now/table/sys_user?sysparm_limit=5&sysparm_query=employee_number=117') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This error message says it was being redirected.

Did you try these appropriate options to handle the http redirects:

Those options should rewrites the protocol/host/port to comply with the CORS policy.

Here are some resource on how redirects work: https://en.wikipedia.org/wiki/HTTP_302 https://stackoverflow.com/questions/3356838/how-does-http-302-work

kobermeit commented 5 years ago

Try using the node cors package. I had to use it in mine to avoid CORS errors, here's a snippet

`var express = require('express'); var proxy = require('http-proxy-middleware'); var cors = require('cors');

var app = express(); app.use(cors())`

frankyfdr commented 4 years ago

On your target, try to use https instead