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/;
}
}
Related
I'm using Protractor to implement end-to-end tests on my AngularJS app using Grunt, and my app does use proxy pass to handle API calls. As a result, when running tests, API calls fail because http://localhost:9000/api is not handled.
I tried the grunt-connect-proxy plugin to handle /api proxy pass but it simply redirects (HTTP code 301) localhost:9000/api to myserver.com/api, and doesn't mimic the behaviour of a proxy pass (and the app doesn't work either).
Here's the Gruntfile configuration:
connect: {
options: {
port: 9000,
hostname: 'localhost',
base: ['<%= globals.appFolder %>/'],
logger: 'dev',
}
},
protractor: {
options: {
configFile: 'tests/e2e/protractor.config.js',
keepAlive: true,
noColor: false,
args: {}
},
e2e: {
options: {
args: {}
}
}
}
And here's the Protractor configuration file:
exports.config = {
specs: ['./suites/*.js'],
baseUrl: 'http://localhost:9000',
maxSessions: 1,
multiCapabilities: [{
browserName: 'chrome'
}],
};
How would you handle this case to let tests run on both a desktop machine, and a remote machine (such as Jenkins)?
According to this issue related on grunt-connect-proxy, this is a bug occurring when dealing with HTTPS endpoints. Use the master/ version instead.
Package.json:
"grunt-connect-proxy": "https://github.com/drewzboto/grunt-connect-proxy#master",
Gruntfile:
proxies: [{
context: '/api',
host: 'myserver.com',
port: 443,
https: true
}]
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
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
I am developing an angularjs site for someone and the site they are going to put it on is something like this
http://domain.com/newsite
So to get my links to work I added the following in the head tags to get the links to work in production
<base href="/newsite/" />
But now when I use grunt connect, nothing works because of that base element. I guess, when I am locally working I could comment it out but I would be concerned I would forget to put it back. Thanks for any tips.
Here is part of my grunt file
connect: {
server: {
options: {
port: '9001',
base: 'build/',
protocol: 'http',
hostname: 'localhost',
livereload: true,
open: {
target: 'http://localhost:9001',
callback: function() {}
},
}
}
},
watch: {
files: [
'<%= app.root %>**/*',
'Gruntfile.js'
],
tasks: [ 'copy', 'less:dev' ],
options: {
reload: false,
livereload: true,
spawn: true
}
}
Posts I checked that did not give me any answers:
grunt-connect: serve files with base url added
I would change the livereload part of your server options to something like the following:
connect: {
server: {
options: {
port: '9001',
base: 'build/',
protocol: 'http',
hostname: 'localhost',
livereload: true,
open: 'http://localhost:9001/newsite/'
}
}
},