28

I'm trying to redirect my API requests like this with gulp and browser-sync:

gulp.task('browser-sync', function () {

   var files = [
      '../index.html',
      '../views/**/*.html',
      '../assets/css/**/*.css',
      '../assets/js/**/*.js'
   ];

   var url = require('url'),
   proxy = require('proxy-middleware');
   var proxyOptions = url.parse('http://localhost:8000/api');
   proxyOptions.route = '/api';

   browserSync.init(files, {
      server: {
         baseDir: '..',
         middleware: [proxy(proxyOptions)]
      }
   });

});

But I get this response when a call is sent to the API:

Error: connect ECONNREFUSED
    at errnoException (net.js:904:11)
    at Object.afterConnect [as oncomplete] (net.js:895:19)

Any idea on what I'm doing wrong?

Armel Larcier
  • 15,747
  • 7
  • 68
  • 89
alskaa
  • 394
  • 1
  • 3
  • 14

3 Answers3

50

Checkout the official documentation about using BrowserSync with Gulp. I was able to get BrowserSync up and running with a proxy on /api with no issue.

Check to make sure nothing else is using port 8000. You can change what port BrowserSync uses via the port option when initializing BrowserSync.

Here is the gulpfile.js I ended up with:

npm install gulp url proxy-middleware browser-sync --save-dev

// Include gulp
var gulp = require('gulp');

var url = require('url');
var proxy = require('proxy-middleware');
var browserSync = require('browser-sync'); 

var paths =  {
    css: ['./**/*.css', '!./node_modules/**/*']
};


// browser-sync task for starting the server.
gulp.task('browser-sync', function() {
    var proxyOptions = url.parse('http://localhost:3000/secret-api');
    proxyOptions.route = '/api';
    // requests to `/api/x/y/z` are proxied to `http://localhost:3000/secret-api/x/y/z`

    browserSync({
        open: true,
        port: 3000,
        server: {
            baseDir: "./",
            middleware: [proxy(proxyOptions)]
        }
    });
});

// Stream the style changes to the page
gulp.task('reload-css', function() {
    gulp.src(paths.css)
        .pipe(browserSync.reload({stream: true}));
});

// Watch Files For Changes
gulp.task('watch', function() {
    gulp.watch(paths.css, ['reload-css']);
});

// Default Task
gulp.task('default', ['browser-sync', 'watch']);

If you do not want to make a separate gulp task to reload/stream the changes, you can use the files option:

browserSync({
    open: true,
    port: 3000,
    server: {
        baseDir: "./",
        middleware: [proxy(proxyOptions)]
    },
    files: paths.css
});
Arnaud P
  • 12,022
  • 7
  • 56
  • 67
MLM
  • 3,660
  • 3
  • 41
  • 66
  • @pjv Give me an example of the url. This works just fine for me: `http://localhost:3000/secret-api/a/b/c/index.html?asfd` – MLM Sep 26 '14 at 23:39
  • browsersync is serving a static site that needs to POST to a flask web app. that flask app is also running on my dev machine on a different port than browsersync. browsersync is running on port 3000, flask on 4000. so i want to route a path that looks like `/charge` (full url: `http://localhost:3000/charge`) to `http://localhost:4000/charge` – pjv Sep 27 '14 at 00:35
  • @pjv Does this work: `var proxyOptions = url.parse('http://localhost:4000/charge'); proxyOptions.route = '/charge';`. I suggest we take this to chat if you need some further help. – MLM Sep 27 '14 at 01:01
  • no, that doesn't work - that's exactly what i have in my gulpfile.js. when i submit the form, nothing hits the flask app. if i change the route to `/charge/` (trailing slash), then it hits the flask app, but the flask app is looking for `/charge` not `/charge/` so it 404's. – pjv Sep 27 '14 at 01:08
  • I just face the same problem with trailing slash. If it absent in the url then proxy doesn't work. This is only for base url. Nested urls working fine even without slash. Are you resolve this issue somehow? – Ruslan Stelmachenko Nov 17 '14 at 17:24
  • @djxak I had no problem setting it up but we never really figured out what was wrong with pjv's setup: http://chat.stackoverflow.com/transcript/message/19137913#19137913 – MLM Nov 17 '14 at 19:58
  • Ok, thanks for sharing it. I think @pjv's [workaround](http://chat.stackoverflow.com/transcript/message/19130016#19130016) will work. – Ruslan Stelmachenko Nov 19 '14 at 04:32
  • Handy to [verify port availability](https://askubuntu.com/questions/278448/how-to-know-what-program-is-listening-on-a-given-port): `sudo lsof -i :8000` – Frank N Jan 06 '17 at 10:53
12

I ran into the same issue with the gulp + browser-sync + proxy-middleware setup, while migrating from grunt to gulp.

Error: connect ECONNREFUSED
    at errnoException (net.js:904:11)
    at Object.afterConnect [as oncomplete] (net.js:895:19)

In my case something within the corporate network which didn't allow proxy-middleware to work. As soon I was on the public network, the issue was gone.

With grunt-connect + grunt-connect-proxy I could proxy files within the corporate network without any problems.

proxy-middleware implements its own proxy functionality, while grunt-connect-proxy uses http-proxy to do the actual proxy work.

I ended up writing a small middleware wrapper around http-proxy to be used in browser-sync and connect, which solved the proxy issues in the corporate network.

https://www.npmjs.com/package/http-proxy-middleware

var browserSync = require('browser-sync');
var proxyMiddleware = require('http-proxy-middleware');

var proxy = proxyMiddleware('/ajax', {target: 'http://cdnjs.cloudflare.com'});

browserSync({
    server: {
        baseDir: "./",
        port: 3000,
        middleware: [proxy]
    }
});
chimurai
  • 1,285
  • 1
  • 16
  • 18
  • 1
    That middleware is awesome, great job! – trysis Jul 07 '15 at 15:32
  • 1
    @Tropicalista If you believe to have found a bug, please create a ticket at: https://github.com/chimurai/http-proxy-middleware/issues – chimurai Aug 12 '15 at 20:39
  • How I can check if it's works normally? I configured proxy but in network/ request URL headers I don't see proxied URL. Only URL to my host, Thanks) – Velidan Jun 15 '16 at 10:39
1

I came across an issue, which I could not find solution for. I need both options:

  1. browser-sync running in SPA mode
  2. there is middleware proxy at /api route

It appears that SPA mode intercepts the /api and renders index.html instead of proxying to backend.

The solution is in browser-sync sources: single mode is implemented using that middleware route, which has higher priority than the ones added manually:

        if (bs.options.get("single")) {
            defaultMiddlewares.unshift({
                id: "Browsersync SPA support",
                route: "",
                handle: require("connect-history-api-fallback")()
            });
        }

Following configuration works as needed - SPA route is at the end of middleware list:

const proxy = require('proxy-middleware');
...
    server.init({
        ...
        middleware: [ {
            route: "/api",
            handle: proxy(url.parse("http://api.host:4444/api"))
        }, {
            id: "SPA support",
            route: "",
            handle: require("connect-history-api-fallback")()
        } ],
        single: false,
        ...
    })

Xtra Coder
  • 3,389
  • 4
  • 40
  • 59