I am trying to configure BrowserSync to work in server mode and to proxy my API requests to the backend that runs on the same machine on a different port, using http-proxy-middleware. I use Gulp to launch BrowserSync.
BrowserSync runs on port 8081. My backend runs on 8080.
Here is how I create the proxy middleware :
var proxyApi = proxy('/api', {target : 'http://localhost:8080/api', logLevel : 'debug'});
And here is how I run BrowserSync from my Gulp task :
// Init BrowserSync with proxies as middleware and based on the dest dir
browserSync.init({
open: true,
port: config.proxyPort,
server: {
baseDir: config.destDir,
middleware: [proxyApi]
},
browser: "google chrome"
});
The output :
[HPM] Proxy created: /api -> http://localhost:8080/api
Everything looks good.
But When I hit e.g. http://localhost:8081/api/users, the output is :
[HPM] GET /api/users/123 -> http://localhost:8080/api
...And my client gets a 404 error because /api on its own does not match anything on the backend.
From what I understood from the doc and examples, the target should actually be http://localhost:8080/api/users/123
Why is the rest of the path (in this case /users/123) being left out ?
Using the following versions :
"gulp": "3.9.1",
"browser-sync": "2.16.0",
"http-proxy-middleware": "0.17.1",
The prependPath option is true by default. This option is provided by the underlying lib: http-proxy.
prependPath: true/false, Default: true - specify whether you want to
prepend the target's path to the proxy path
There are two ways to fix the issue:
1.) Change your target from 'http://localhost:8080/api' to 'http://localhost:8080'
var proxyApi = proxy('/api', {target: 'http://localhost:8080', logLevel: 'debug'});
2.) Alternatively you can set the option prependPath to false.
var proxyApi = proxy('/api', {target: 'http://localhost:8080/api', prependPath: false, logLevel: 'debug'});
Related
How do I set up a proxy using WebpackDevServer in my React/Node chrome extension? My server is run on localhost:4000 and React frontend on localhost:5000
Using Axios, I try and hit the route: axios.get(/api/user/ticket), however, localhost:4000 is not proxied and the route that is hit is my chrome extension: chrome-extension://fjkfhdsjkwerjhdksfhdjkshfds/api/ticket/user/.
If I explicitly call localhost: axios.get(localhost:4000/api/user/ticket), then everything works properly. I'm new to webpack so not fully sure what I'm doing wrong. Thank you for the help!
Webserver proxy implemented using the docs
var server = new WebpackDevServer(
{
https: false,
hot: false,
client: false,
proxy: {
'/api': 'http://localhost:4000',
},
host: 'localhost',
port: env.PORT,
static: {
directory: path.join(__dirname, '../build'),
},
devMiddleware: {
publicPath: `http://localhost:${env.PORT}/`,
writeToDisk: true,
},
headers: {
'Access-Control-Allow-Origin': '*',
},
//this needs to change to prevent dns attacks
allowedHosts: 'all',
},
compiler
);
Proxy still doesn't work, however, I got around this by using baseUrls in axios. When in prod vs dev I just have to change them in one place and it works. Not ideal but it gets the job done.
In a create-react-app, I can use proxy in package.json to configure a proxy automatically, as described in here https://create-react-app.dev/docs/proxying-api-requests-in-development/
This allow me to serv my app from a different port.
How can I do the same configuration without create-react-app?
It would be nice to have the same proxy to benefit the same configuration as in with create-react-app.
You can create a file to run with node to act as your proxy. Like this:
proxy.js
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer({
secure: false,
changeOrigin: true,
target: 'https://someOriginURL.com',
// could be an IP address target: 'https://XX.XX.XXX.XXX/',
}).listen(3500, () => console.log('Proxy running on port 3500'));
// Intercepts the request
proxy.on('proxyReq', function(proxyReq, req, res, options) {
console.log(req);
// Set the headers of the intercepted request
proxyReq.setHeader('Origin', 'https://yourorigin.com');
// remove any headers you want
// proxyReq.removeHeader('authorization');
res.oldWriteHead = res.writeHead;
res.writeHead = function(statusCode, headers) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.oldWriteHead(statusCode, headers);
}
});
to use this open a terminal and run:
node proxy.js
P.S.: Don't use this in production :D
My app was written on top of vuejs-templates/pwa boilerplate.
I've added a proxy to dev server config (build/webpack.dev.conf.js):
devServer: {
proxy: {
'/api': {
target: 'https://staging-api.company.net',
pathRewrite: {"^/api": ""},
secure: true,
changeOrigin: true,
},
},
},
It obviously doesn't work on first try, but I want to debug it to know how the proxy is redirecting the requests. I'd like to see in command line output some logs, something like:
Redirecting from /api/user/bla to https://staging-api.company.net/user/bla
But currently when I run yarn dev, when compilation is done all I see is:
Listening at http://localhost:8000
and after that the cli is silent.
I've tried to add an option to webpack-dev-middleware in build/dev-server.js:
const devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
// quiet: true,
logLevel: 'debug',
});
but it doesn't help, I'm not getting any new output in cli when I trigger requests from my app.
I have a problem using gulp-livereload in my vagrant environment (generated with puphpet).
My computer is a Windows Host, and the VM a Debian.
I use this gulpfile :
var gulp = require('gulp'),
less = require('gulp-less')
lr = require('tiny-lr'),
livereload = require('gulp-livereload'),
server = lr()
;
gulp.task('less', function () {
gulp.src('assets/less/*.less')
.pipe(less())
.pipe(gulp.dest('build/css'))
.pipe(livereload(server))
;
});
gulp.task('watch', function() {
gulp.watch('assets/less/*.less', ['less']);
livereload.listen(35729, function(err){
if(err) return console.log(err);
});
});
gulp.task('default', ['watch', 'less']);
And when Chrome Extension add the magic JS file I obtain this message :
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT http://markup.dev:35729/livereload.js?ext=Chrome&extver=0.0.5
But in my VM, if I run the following command line, I get it
wget http://localhost:35729/livereload.js?ext=Chrome&extver=0.0.5
I don't have enough information to be certain, but I would guess that your problem is you are trying to access the page from the host, but the livereload port isn't forwarded (the VM has it's own IP address and vagrant can be configured to forward certain ports to the host so that they "appear" to be local on the host).
Try adding the following line to your Vagrantfile:
config.vm.network "forwarded_port", guest: 35729, host: 35729
(For documentation see: https://docs.vagrantup.com/v2/networking/forwarded_ports.html)
Alternatively if you are directly hitting the VM (that is you have markup.dev mapped to the guest's IP) it may be worth verifying that there is not a firewall configured on your VM which might block the livereload port from external access.
In my case, the port forwarding worked automagically. However, I had to specify the VM's IP as host:
livereload.listen({
host: '192.168.33.10'
});
Update: Passing null works, too:
livereload.listen({
host: null
});
I guess that the underlying http server behaves differently when passing 'localhost' explicitly.
I setup Yeoman 1.0 beta to handle my js/css tasks. Everything works fine that, if I run grunt server, it starts up a static server and connects a browser session to port 9000 (livereload). js/css concat, minification are also working.
Now, is there a way I can make it to connect to a google app engine development server (instead of starting a static server). The server is running at port 8080 on localhost, and I want grunt to reload the webpage upon css/js files under watch. These files would be served by GAE server.
I see a section rolling your own at grunt-contrib-connect documentation, but not sure it means an external server. As far as I see, these are the relavent configuration from Gruntfile.js
connect: {
livereload: {
options: {
port: 8080, //*** was 9001 originally **
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app)
];
}
}
},
When I change the port number to 8080, and try to start, obviously it gives error.
Fatal error: Port 8080 is already in use by another process.
so, I don't want to start a new server, but connect through GAE server already running.
Thanks.
In order to use GAE server instead of nodejs server, we need to do the following.
* Compile your less/coffeescript, concat[, minify], copy your code to the location where the app engine code resides.
* Create a task in grunt.js to spawn a shell command to run app engine.
This is the example, that I used as reference. https://github.com/cowboy/grunt/tree/master/tasks
Following grunt.js file may help!
module.exports = function(grunt) {
grunt.initConfig({
....
});
grunt.registerTask('appengine-update', 'Upload to App Engine.', function() {
var spawn = require('child_process').spawn;
var PIPE = {stdio: 'inherit'};
var done = this.async();
spawn('appcfg.py', ['update', 'build/task-manager-angular'], PIPE).on('exit', function(status) {
done(status === 0);
});
});
grunt.registerTask('clean', 'Clean the whole build directory.', function() {
require('child_process').exec('rm -rdf build', this.async());
});
grunt.registerTask('run', 'Run app server.', function() {
var spawn = require('child_process').spawn;
var PIPE = {stdio: 'inherit'};
var done = this.async();
spawn('dev_appserver.py', ['.'], PIPE).on('exit', function(status) {
done(status === 0);
});
});
});
//....
//Other settings
//....
grunt.loadTasks('tasks');
grunt.loadNpmTasks('grunt-coffeelint');
grunt.registerTask('build', 'coffee less concat');
grunt.registerTask('deploy', 'coffee less concat build appengine-update');
grunt.registerTask('default', 'coffee less');
};
Found this Google App Engine management plugin for Grunt