I'm using grunt-connect-proxy "^0.2.0" to proxy to an api from my angularjs application. The project was started with yeoman angular-generator.
I've followed the instructions here but when the proxy is used, I get:
Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:9000/api/users
My Proxy Configuration:
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
proxies: [{
context: '/api', // the context of the data service
host: 'localhost', // wherever the data service is running
port: 8080, // the port that the data service is running on
https: false,
xforward: false
}],
My Middleware:
livereload: {
options: {
open: true,
base: '',
middleware: function (connect, options) {
var middlewares = [];
middlewares.push(require('grunt-connect-proxy/lib/utils').proxyRequest);
middlewares.push(connect.static('.tmp'));
middlewares.push(connect.static('test'));
middlewares.push(connect().use(
'/bower_components',
connect.static('./bower_components')
));
middlewares.push(connect.static(appConfig.app));
return middlewares;
}
}
},
My Serve Task
grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer:server',
'configureProxies:server',
'connect:livereload',
'watch'
]);
});
EDIT
localhost:8080/users returns a 403 currently via Postman, so the API is running.
not directly answering your question but providing a solution (since noone else has answered) ... have you tried the npm module connect-modrewrite
this does exactly what you are trying to do.
I was having the same issue i resolve this way and its work for me. Look into my code below:-
connect: {
server: {
options: {
keepalive: true,
port: 8001,
protocol: 'http',
hostname: '*',
directory: 'dist',
open: {
target: 'http://localhost:8001/myDemo.html',
},
middleware: function(connect, options, middlewares) {
middlewares.unshift(function(req, res, next) {
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
**if (req.method.toUpperCase() == 'POST') req.method='GET';**
return next();
});
return middlewares;
}
}
}
},
see the star marked line ie if (req.method.toUpperCase() == 'POST') req.method='GET'; i done this trick and its worked for me. This aricle also helps to me https://github.com/gruntjs/grunt-contrib-connect#middleware
Related
I have a web application with front end based on angular and back end as a spring rest API. I'm using grunt connect to serve the front end while the rest api runs on localhst:8080, the grunt server runs on localhost:9002.
So from angular, when I'm sending an http call to the back end server using angular-resource, I'm getting following error :
Failed to load localhost:8080/api/v1/user: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https
angular.js:14800 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"localhost:8080/api/v1/user","data":{"user":{"email":"a","password":"a"}},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json;charset=utf-8"}},"statusText":"","xhrStatus":"error","resource":{"user":"..."}}
JS File :
angular.module('userModule').factory('userService',function($resource){
var dataResource = $resource('user',{},
{
saveUser :{
method: 'POST',
url:'localhost:8080/api/v1/user',
params : '#user'
},
});
return dataResource;
});
Gruntfile
'use strict';
module.exports = function (grunt) {
var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest;
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
var serveStatic = require('serve-static');
// Define the configuration for all the tasks
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
clean: ["dist"],
htmlmin: { // Task
dist: { // Target
options: { // Target options
removeComments: true,
collapseWhitespace: true
},
files: { // Dictionary of files
'dist/index.html': 'dist/index.html' // 'destination': 'source'
}
}
},
copy: {
main: {
expand: true,
cwd: '.',
src: ['**', /* '!js/**', '!lib/**', */ '!**/*.css', '!node_modules/**', '!Gruntfile.js', '!package.json', '!package-lock.json'],
dest: 'dist/'
},
fonts: {
expand: true,
cwd: 'lib/fonts',
src: ['**'],
dest: 'dist/fonts'
}
},
rev: {
files: {
src: ['dist/**/*.{js,css}', '!dist/lib/**/*.{js,css}', '!dist/js/services/**/*.{js,css}']
}
},
useminPrepare: {
html: 'index.html'
},
usemin: {
html: ['dist/index.html']
},
uglify: {
options: {
report: 'min',
mangle: false
}
},
// Watches files for changes and runs tasks based on the changed files
watch: {
js: {
files: ['js/*.js'],
options: {
livereload: '<%= connect.options.livereload %>'
}
},
styles: {
files: ['css/*.css']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'*.html',
'css/*.css',
'images/*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9002,
// Change this to '0.0.0.0' to access the server from outside.
hostname: '0.0.0.0',
livereload: 35730,
base: '.',
middleware: function (connect, options, middlewares) {
middlewares.unshift(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', '*');
return next();
});
return middlewares;
}
},
proxies: [
{
context: '/api/v1',
host: 'localhost',
port: 8080,
changeOrigin: true
}
],
livereload: {
options: {
open: false,
middleware: function (connect) {
return [
proxySnippet,
serveStatic('.')
];
}
}
}
},
});
grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
grunt.task.run([
'configureProxies',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('default', [
'clean', 'copy', 'useminPrepare', 'concat', 'uglify', 'cssmin', 'rev', 'usemin', 'htmlmin'
]);
};
Can some one tell me is it possible to send http calls with grunt connect?
You are running into CORS issue, This happens when you are making request to a different domain or schema http https or different port (your case falls in this). There are two options.
Allow CORS on your backend server (spring backed server in your case).
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors().and()
...
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Further information can be found here.
Configure Front end and backend in same full fledged HTTP server like apache, nginx and setup the request handling as below.
a. Serve all static/angular resources on default path. (localhost/)
b. Send all your backend request to localhost/api/ and proxy it to your backend localhost:8080/api application.
Nginx example:
server {
listen 80;
# The host name to respond to
server_name localhost;
location /api/ {
# Backend nodejs server
proxy_pass http://localhost:8080/api;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location / {
root /angular directory path/;
}
}
I am running my application with grunt task runner, it throws me following error:
POST http://localhost:8080/stub/cms/myalerts2.json 405 (Method Not Allowed)
I have tried following things in my Gruntfile.js
connect: {
server: {
options: {
keepalive: true,
port: 8001,
protocol: 'http',
hostname: '*',
base: 'dis',
directory: 'dis',
open: {
target: 'http://localhost:8001/mydemo.html',
appname: 'open'
},
middleware: function(connect, options, middlewares) {
middlewares.unshift(function(req,res,next){
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,PUT,POST,DELETE');
res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers']);
});
return middlewares;
}
}
}
},
Still its not allowing me to run. Any help or suggestion will me most welcome. Thanks in advance
So far i have tried following updation to my code, i am able to get rid of Method not Allowed 405 Error but currently i am getting "Failed to load resource: the server responded with a status of 404 (Not Found)"
i have modified my code as below:-
connect: {
server: {
options: {
keepalive: true,
port: 8001,
protocol: 'http',
hostname: '*',
base: 'dist',
directory: 'dist',
open: {
target: 'http://localhost:8001/myDemo.html',
appname: 'open'
},
middleware: function(connect, options, next) {
return [
function(req, res, next) {
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
next();
}];
}
}
}
},
Any suggestion will be appreciated.
After couple of irritating days finally my code works for me. Look into my code below:-
connect: {
server: {
options: {
keepalive: true,
port: 8001,
protocol: 'http',
hostname: '*',
directory: 'dist',
open: {
target: 'http://localhost:8001/myDemo.html',
},
middleware: function(connect, options, middlewares) {
middlewares.unshift(function(req, res, next) {
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
**if (req.method.toUpperCase() == 'POST') req.method='GET';**
return next();
});
return middlewares;
}
}
}
},
see the star marked line ie if (req.method.toUpperCase() == 'POST') req.method='GET'; i done this trick and its worked for me.
This aricle also helps to me https://github.com/gruntjs/grunt-contrib-connect#middleware
I am using webpack-dev-server v1.10.1 to boost up my Redux project and I have the options below:
contentBase: `http://${config.HOST}:${config.PORT}`,
quiet: false,
noInfo: true,
hot: true,
inline: true,
lazy: false,
publicPath: configWebpack.output.publicPath,
headers: {"Access-Control-Allow-Origin": "*"},
stats: {colors: true}
In the JS, I am using request from superagent to generate a HTTP GET call
request
.get(config.APIHost + apiUrl)
.set('Accept', 'application/json')
.withCredentials()
.end(function (err, res) {
if (!err && res.body) {
disptach(() => {
return {
type: actionType || GET_DATA,
payload: {
response: res.body
}
}
});
}
});
But I got the CORS error:
XMLHttpRequest cannot load http://localhost:8000/api/getContentByType?category=all. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5050' is therefore not allowed access
Any suggestion to resolve this? Thanks a lot
Another way to work around it is to directly add the required CORS headers to the dev server:
devServer: {
...
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
}
}
Doc links
Webpack dev server
Access-Control-Allow-Headers
Access-Control-Allow-Methods
Access-Control-Allow-Origin
With webpack-dev-server 1.15.X you can use this configuration in your config file:
devServer: {
contentBase: DIST_FOLDER,
port: 8888,
// Send API requests on localhost to API server get around CORS.
proxy: {
'/api': {
target: {
host: "0.0.0.0",
protocol: 'http:',
port: 8080
},
pathRewrite: {
'^/api': ''
}
}
}
},
With this example you will redirect all calls from http://0.0.0.0:8888/api/* to http://0.0.0.0:8080/* and CORS solved
Had the same issue, but my api was on a https protocol (https://api....). Had to start the server with https and use https://localhost:8080
devServer: {
https: true,
headers: {
"Access-Control-Allow-Origin": "*",
},
// ....
}
You're running your JavaScript from localhost:5050 but your API server is localhost:8000. This violates the same origin policy, so the browser disallows it.
You can either modify your API server so that CORS is enabled, or follow the instructions on the webpack-dev-server page under "Combining with an existing server" to combine asset serving with webpack-dev-server and your own API server.
There are 2 solutions for this. first one is setting up proxy on the client side, second one is setting CORS on the server. CORS is server issue, server does not allow access from different source. Even using different ports is considered to be different source
First Solution
IN your backend code, you have to set this headers: this is example of in express node.js
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE"
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
Second Solution:
in webpack config.js, if you want to pass any variable, we export
module.exports=function(env){
return {}}
instead of
module.exports={}
we inject this env through the script.
"dev-server": "webpack-dev-server --env.api='https://jsonplaceholder.typicode.com/users'",
now webpack has access to this env. in webpack.config.js
module.exports = function ({
api = "https://jsonplaceholder.typicode.com/users",
}) {
return {
entry: { main: "./src/index.js" },
output: {
path: path.resolve(__dirname, "public"),
filename: "[name]-bundle.js",
publicPath: "/",
},
mode: "development",
module: {
rules: [
{
loader: "babel-loader",
test: /\.js$/,
exclude: [/node_modules/],
},
{
// Load other files, images etc
test: /\.(png|j?g|gif|ico)?$/,
use: "url-loader",
},
{
test: /\.s?css$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
//Some JavaScript bundlers may wrap the application code with eval statements in development.
//If you use Webpack, using the cheap-module-source-map setting in development to avoid this problem
devtool: "cheap-module-eval-source-map",
devServer: {
contentBase: path.join(__dirname, "public"),
historyApiFallback: true,
proxy: {
"/api": {
changeOrigin: true,
cookieDomainRewrite: "localhost",
target: api,
onProxyReq: (proxyReq) => {
if (proxyReq.getHeader("origin")) {
proxyReq.setHeader("origin", api);
}
},
},
},
},
};
};
I am working with a yeoman generator-angular app and a remote API, my gruntfile config seems to be fine:
// Generated on 2015-06-01 using generator-angular 0.11.1
'use strict';
module.exports = function (grunt) {
/ * Removed for brevity */
grunt.initConfig({
yeoman: appConfig,
watch: {
/ * Removed for brevity */
},
connect: {
options: {
port: 9000,
hostname: 'localhost',
livereload: 35729
},
proxies: [
{
context: '/api',
host: 'subdomain.hostname.com',
xforward: true,
secure: false,
headers: {
'Authorization': 'RemovedToken'
},
}
],
livereload: {
options: {
open: true,
middleware: function (connect, options) {
var middlewares = [require('grunt-connect-proxy/lib/utils').proxyRequest];
middlewares.push(
connect.static('.tmp'),
connect().use('/bower_components',connect.static('./bower_components')),
connect().use('/app/styles', connect.static('./app/styles')),
connect().use(connect.static(appConfig.app))
);
return middlewares;
}
}
},
/ * Removed for brevity */
},
/ * Removed for brevity */
});
grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer:server',
'configureProxies:server',
'connect:livereload',
'watch'
]);
});
grunt.loadNpmTasks('grunt-connect-proxy');
};
grunt serve --verbose returns this when a request is made:
Proxied request: /api/foo/bar/?baz=6 -> http://subdomain.hostname.com:80/api/foo/bar/?baz=6
{
"host": "localhost:9000",
"connection": "keep-alive",
"accept": "application/json, text/plain, */*",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36",
"referer": "http://localhost:9000/",
"accept-encoding": "gzip, deflate, sdch",
"accept-language": "en-US,en;q=0.8,es;q=0.6",
"cookie": "connect.sid=s%3AQpOp8pdI8GM2g8s0qCX602-ds-Xs-5le.C%2BrosIxHQ4ZcLLPgZKhABjji18kqK2K73C7mjF6scqM",
"Authorization": "RemovedToken",
"x-forwarded-for": "127.0.0.1",
"x-forwarded-port": "9000",
"x-forwarded-proto": "http"
}
I can't find any error there, maybe that the "host" is still localhost:9000, but I'm unsure if that could be a problem and in Chrome I am getting: 503 Service Unavailable, but there is indeed a service running, I know because I tested it with Postman and everything works fine, could somebody help me with this? Maybe I am missing something in the configuration?
Thanks.
After digging some more in the project I found that I had to specify the "host" header too.
https://github.com/drewzboto/grunt-connect-proxy/issues/72
I have currently a simple angular application configured with yeoman, and the only customisation I'm trying is with grunt-connect-proxy. So I followed the instructions and modified my Gruntfile :
var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest;
module.exports = function (grunt) {
...
grunt.initConfig({
...
connect: {
...
server: {
proxies: [
{
context: '/api',
host: 'somevirtualhost',
port: 8080,
https: false,
changeOrigin: true
}
]
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
proxySnippet,
...
];
}
}
},
...
},
});
...
grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
...
grunt.task.run([
...
'configureProxies:server',
...
]);
});
}
And in a controller I tried the following :
var Versions = $resource('/api/version/:versId', { versId: '#id' });
var version = Versions.get({ versId: 'Ultra' }, function () {
console.log('here I am');
});
When I run grunt serve I can see the proxy is created :
Running "configureProxies:server" (configureProxies) task
Proxy created for: /api to somevirtualhost:8080
But in the console of the web page I get :
Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:9000/api/version/Ultra
Any idea ?
I found some clues here : https://github.com/drewzboto/grunt-connect-proxy/issues/69
I don't understand everything but for now I add the headers option in my proxies :
proxies: [
{
context: '/api',
host: 'somevirtualhost',
port: 8080,
https: false,
changeOrigin: true,
headers: {
'host': 'somevirtualhost'
},
}
]
And it seems to work