Ido Ran
Ido Ran

Reputation: 11384

create-react-app proxy works only with fetch api but not in simple get of the browser

I'm using pretty small create-react-app running on port 3000 setup to proxy requests to backend server running on port 8080. If I put in the browser address bar http://localhost:3000/api/me I get back the index.html page but if I use fetch API to get /api/me it try to call to by backend.

The problem is that I have to authenticate with the backend which will set a cookie but since I can't access the login page on http://localhost:3000/login I can't get the cookie.

On a different project which I've eject from create-react-app I have small file to run webpack-dev-server wih the configuration

  proxy: {
    "*": "http://localhost:9191"
  }

which does proxy requests even when put into the browser address bar.

Is it possible to create such setup in create-react-app?

Upvotes: 13

Views: 10247

Answers (4)

Vivek
Vivek

Reputation: 13238

Yes it is possible. You will need to use http-proxy-middleware and configure proxy manually.

First install http-proxy-middleware in your react app

npm install http-proxy-middleware --save

Then create src/setupProxy.js file with below configuration

/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable no-undef */
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:9191',
      secure: false,
      changeOrigin: true,
    })
  );
};

Now simply start the application and you will see that non AJAX calls (document etc) are also being proxied correctly.

Note: Remove the proxy configuration from package.json file before configuring it manually with http-proxy-middleware otherwise the proxy won't work correctly if defined at both the places

Upvotes: 0

Nick
Nick

Reputation: 19

Yes it is possible:

  "proxy": {
    "/api": {
      "target": "<url>",
      "ws": true
    }
  },

See https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#configuring-the-proxy-manually

Upvotes: 1

badal jain
badal jain

Reputation: 53

I have my own react app and I tried adding proxy to the package.json, but it is nit working.

The simple create-react-app works just fine bu tit does not have any webpack configured.

Here is my webpack:

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
  template: './src/index.html',
  filename: 'index.html',
  inject: 'body'
})

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve('./dist'),
        filename: 'index_bundle.js'
    },
    module: {
        loaders:[
            { 
                test: /\.js$/, 
                loader: 'babel-loader', 
                exclude: /node_modules/ 
            },
            { 
                test: /\.jsx$/, 
                loader: 'babel-loader', 
                exclude: /node_modules/ 
            },
            { 
                test: /\.css$/, 
                loader: "style-loader!css-loader?modules" 
            },
            { 
                test: /\.png$/, 
                loader: "url-loader?limit=100000" 
            },
            { 
                test: /\.jpg$/, 
                loader: "file-loader" 
            },
            {
                test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'url-loader?limit=10000&mimetype=application/font-woff'
            },
            {
                test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
            },
            {     
                test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'file-loader'
            },
            {
                test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 
                loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.jsx' ,'.json'],
        modules: [path.join(__dirname, 'src'), 'node_modules']
    },
    plugins: [HtmlWebpackPluginConfig]
}

My package.json:

{
  "name": "A2ZPressMaterial",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "webpack-dev-server --history-api-fallback",
    "webpack-watch": "webpack -w",
    "express-server": "node ./server",
    "dev": "concurrently --kill-others \"npm run webpack-watch\" \"npm run express-server\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "proxy": "http://localhost:3001",
  "dependencies": {
    "classnames": "^2.2.5",
    "css-loader": "^0.28.7",
    "file-loader": "^0.11.2",
    "html-webpack-plugin": "^2.30.1",
    "http-proxy-middleware": "^0.17.4",
    "material-ui": "^0.19.2",
    "path": "^0.12.7",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-lazyload": "^2.2.7",
    "react-redux": "^5.0.6",
    "react-router-dom": "^4.2.2",
    "redux": "^3.7.2",
    "redux-thunk": "^2.2.0",
    "style-loader": "^0.18.2",
    "url-loader": "^0.5.9",
    "webpack": "^3.5.6",
    "webpack-dev-server": "^2.8.1"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "concurrently": "^3.5.0"
  }
}

I get 404 on my ajax/fetch calls

Upvotes: 0

Ido Ran
Ido Ran

Reputation: 11384

Closer look into create-react-app code reveal that this is by design:

For single page apps, we generally want to fallback to /index.html. However we also want to respect proxy for API calls. So if proxy is specified, we need to decide which fallback to use. We use a heuristic: if request accepts text/html, we pick /index.html. Modern browsers include text/html into accept header when navigating. However API calls like fetch() won’t generally accept text/html. If this heuristic doesn’t work well for you, don’t use proxy.

Running GET of http://localhost:3000/api/me inside REST Console extension return the correct result.

Further reading about Fetch API and cookies reveal that I have to include the parameter credentials:true to send cookies:

fetch('/api/me', {
  credentials: 'include'
})

Upvotes: 19

Related Questions