mars / create-react-app-buildpack

⚛️ Heroku Buildpack for create-react-app: static hosting for React.js web apps
MIT License
3.28k stars 653 forks source link

Proxy to API not working #116

Closed preetom1 closed 6 years ago

preetom1 commented 6 years ago

Hi,

I have a very similar problem to #111, but after reading through that one I still am unable to figure out why my setup isn't working. I have a Flask API set up at a different URL from my frontend React app, and the frontend app makes requests to the backend app through the Axios library. The requests look like this:

axios.post('/api/analyze', data)
.then((response) => {
    if (response.status === 201) {
        this.props.handler(response);
    }
})

Here is my static.json:

{
  "root": "build/",
  "proxies": {
    "/api/": {
      "origin": "https://star-employees-api.herokuapp.com"
    }
  }
}

Here is my package.json:

{
  "name": "heroku-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "axios": "^0.18.0",
    "bootstrap": "^4.1.2",
    "plotly.js": "^1.39.2",
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-plotly.js": "^2.2.0",
    "react-scripts": "1.1.4",
    "reactstrap": "^6.3.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "proxy": "http://0.0.0.0:8000"
}

This is the output from git push heroku master:

Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 380 bytes | 380.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> React.js (create-react-app) multi app detected
remote: -----> Configure create-react-app build environment
remote:        Using `NODE_ENV=development`
remote: =====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-multi.git
remote: =====> Detected Framework: Multipack
remote: =====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-nodejs.git
remote: =====> Detected Framework: Node.js
remote:
remote: -----> Creating runtime environment
remote:
remote:        NPM_CONFIG_LOGLEVEL=error
remote:        NPM_CONFIG_PRODUCTION=false
remote:        NODE_VERBOSE=false
remote:        NODE_ENV=development
remote:        NODE_MODULES_CACHE=true
remote:
remote: -----> Installing binaries
remote:        engines.node (package.json):  unspecified
remote:        engines.npm (package.json):   unspecified (use default)
remote:
remote:        Resolving node version 8.x...
remote:        Downloading and installing node 8.11.3...
remote:        Using default npm version: 5.6.0
remote:
remote: -----> Restoring cache
remote:        Loading 2 from cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (not cached - skipping)
remote:
remote: -----> Building dependencies
remote:        Installing node modules (package.json + package-lock)
remote:        up to date in 14.968s
remote:
remote: -----> Caching build
remote:        Clearing previous node cache
remote:        Saving 2 cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (nothing to cache)
remote:
remote: -----> Pruning devDependencies
remote:        Skipping because NODE_ENV is not 'production'
remote:
remote: -----> Build succeeded!
remote: =====> Downloading Buildpack: https://github.com/mars/create-react-app-inner-buildpack.git
remote: =====> Detected Framework: React.js (create-react-app)
remote:        Using existing `static.json`
remote:        Enabling runtime environment variables
remote:
remote: > heroku-app@0.1.0 build /tmp/build_2849f18a69f6d413f95d175e6372d671
remote: > react-scripts build
remote:
remote: Creating an optimized production build...
remote: Compiled successfully.
remote:
remote: File sizes after gzip:
remote:
remote:   890.5 KB  build/static/js/main.cf69c670.js
remote:   21.13 KB  build/static/css/main.23d8bf43.css
remote:
remote: The bundle size is significantly larger than recommended.
remote: Consider reducing it with code splitting: https://goo.gl/9VhYWB
remote: You can also analyze the project dependencies: https://goo.gl/LeUzfb
remote:
remote: The project was built assuming it is hosted at the server root.
remote: You can control this with the homepage field in your package.json.
remote: For example, add this to build it for GitHub Pages:
remote:
remote:   "homepage" : "http://myname.github.io/myapp",
remote:
remote: The build folder is ready to be deployed.
remote: You may serve it with a static server:
remote:
remote:   npm install -g serve
remote:   serve -s build
remote:
remote: Find out more about deployment here:
remote:
remote:   http://bit.ly/2vY88Kr
remote:
remote: =====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-static.git
remote: =====> Detected Framework: Static HTML
remote:   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
remote:                                  Dload  Upload   Total   Spent    Left  Speed
remote: 100  838k  100  838k    0     0  5320k      0 --:--:-- --:--:-- --:--:-- 5307k
remote: -----> Installed directory to /app/bin
remote: Using release configuration from last framework (Static HTML).
remote: -----> Discovering process types
remote:        Procfile declares types     -> (none)
remote:        Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote:        Done: 88M
remote: -----> Launching...
remote:        Released v21
remote:        https://secure-temple-75313.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/secure-temple-75313.git
   12f422a..f8fed1e  master -> master

Seems to deploy fine. Finally, here are the logs from my backend app:

2018-08-12T16:51:12+00:00 app[heroku-redis]: source=REDIS addon=redis-rigid-46144 sample#active-connections=1 sample#load-avg-1m=0.145 sample#load-avg-5m=0.15 sample#load-avg-15m=0.14 sample#read-iops=0 sample#write-iops=0 sample#memory-total=15664360kB sample#memory-free=11480812kB sample#memory-cached=1168868kB sample#memory-redis=278328bytes sample#hit-rate=1 sample#evicted-keys=0
2018-08-12T16:52:14.026411+00:00 heroku[router]: at=info method=POST path="/analyze" host=star-employees-api.herokuapp.com request_id=44530a5a-a98c-4409-8018-0b02cce7fa69 fwd="68.49.171.127,54.224.104.71" dyno=web.1 connect=0ms service=2ms status=404 bytes=386 protocol=https
2018-08-12T16:52:14.025145+00:00 app[web.1]: 10.182.199.117 - - [12/Aug/2018:16:52:14 +0000] "POST /analyze HTTP/1.1" 404 233 "https://secure-temple-75313.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
2018-08-12T16:52:32.944853+00:00 heroku[router]: at=info method=POST path="/analyze" host=star-employees-api.herokuapp.com request_id=fd92a1d8-c4fc-4299-bf40-63ea37a0d1e5 fwd="68.49.171.127,54.224.104.71" dyno=web.1 connect=0ms service=3ms status=404 bytes=386 protocol=https
2018-08-12T16:52:32.944203+00:00 app[web.1]: 10.65.100.84 - - [12/Aug/2018:16:52:32 +0000] "POST /analyze HTTP/1.1" 404 233 "https://secure-temple-75313.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"

The strange thing to me is that my logs on the backend seem to be recording the requests when I try to use the client app, even though the request fails and the console prints xhr.js:178 POST https://secure-temple-75313.herokuapp.com/api/analyze 404 (NOT FOUND). I would think if the request wasn't being sent to the API it wouldn't show up in the logs at all, but it looks like it does. But on the other hand, if it is sending the request, then I am not sure why the console is giving me a 404 for the client URL if it's being sent to the right place. Also, the logs are logging requests to /analyze, when the calls to in the React code are to /api/analyze.

For reference, everything works fine when I run things locally and use the proxy in my webpack dev server.

I would appreciate any insight into what's happening/how to fix this issue, thanks in advance!

mars commented 6 years ago

Hi @preetom1 😄

If it works locally with a proxy, but not when deployed to Heroku, then there's an inconsistency between your proxy configurations, or otherwise a difference between what's local vs deployed.

It looks like your local dev proxy declared in package.json does not follow what is described in this buildpack's README Proxy for local development. Your local proxy sends all unhandled requests to the backend, but when deployed to Heroku only /api/ prefixed paths get proxied.

The intended proxy behavior is that all requests to /api/* get proxied to the backend without the /api prefix. That prefix prevents unintentional mistakes with overlaying frontend routes with backend routes. In other words, for the request to POST /api/analyze the backend will receive POST /analyze.

So, I think the solution is to:

  1. set package.json proxy config to what's documented in Proxy for local development
  2. change the backend route to match POST /analyze (instead of POST /api/analyze)
preetom1 commented 6 years ago

@mars thank you! You were correct in that there was a disconnect between my local and deployed configurations. I should have realized that the requests to /api/* were getting proxied without the prefix. I followed your steps and the app seems to be working correctly now.

I'll follow up here if I encounter any other related problems, and thanks again! 😃

saket-shetty commented 4 years ago

@mars thank you! You were correct in that there was a disconnect between my local and deployed configurations. I should have realized that the requests to /api/* were getting proxied without the prefix. I followed your steps and the app seems to be working correctly now.

I'll follow up here if I encounter any other related problems, and thanks again! 😃

hey can you share your code please my app is still not working after all the corrections

preetom1 commented 4 years ago

Unfortunately I can't share the code since it's part of a private project I'm no longer working on 😕 Best of luck!