I am trying to send a request from my Webstorm application to my backend application, which both are at different ports, I am working with angularJS in the front end and java in backend. I have read up a bit about CORS Filters and I learned that in order to do Cross Origin Requests I need to implement these. However, after doing this my error, being
Failed to load resource: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63343' is therefore not allowed access. http://localhost:8080/register?password=&username= XMLHttpRequest cannot load http://localhost:8080/register?password=&username=. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63343' is therefore not allowed access.
did not change at all which led me to believe I have done something wrong, here is the code from which I am sending the request:
var charmanderServices = angular.module('charmanderServices', ['ngResource']); var hostAdress = "http://localhost:8080"; charmanderServices.factory("register", ["$resource", function($resource){ console.log('in service'); return $resource(hostAdress + "/register", {}, { 'registerUser' : { method: 'POST', isArray: false, params: { username: '@username', password: '@password' } }, headers : {'Content-Type' : 'application/x-www-form-urlencoded'} }); } ]);
My corsFilter is written like this:
@Component public class SimpleCORSFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { //This is not even printing System.out.println("Cheers lads, I'm in the filter"); HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with, X-Auth-Token, Content-Type"); chain.doFilter(req, res); } public void init(FilterConfig filterConfig) {} public void destroy() {} }
This is my web.xml:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"> <display-name>Project</display-name> <!-- Load Spring Contexts --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- CORS Filter --> <filter> <filter-name>cors</filter-name> <filter-class>com.robin.filters.SimpleCORSFilter</filter-class> </filter> <filter-mapping> <filter-name>cors</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
This is the controller where I am catching the request:
@Controller public class UserController { @Autowired private UserService userService; @RequestMapping(value = "/register" , method= RequestMethod.POST, produces = "application/json") @ResponseBody public boolean register(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password){ System.out.println("Im in register hurray"); return userService.register(username, password); } }
Update: I have tried implementing the filter as a OncePerRequestFilter, still doesn't work. Is anyone able to help me further here?
Update#2: Also tried this one, http://software.dzhuvinov.com/cors-filter-installation.html, no luck
Update#3: This was my output in the console, I can see that the response did not add any headers:
Request URL:http://localhost:8080/register?password=g&username=g Request Method:OPTIONS Status Code:200 OK Request Headersview source Accept:*/* Accept-Encoding:gzip,deflate,sdch Accept-Language:en-US,en;q=0.8,nl;q=0.6 Access-Control-Request-Headers:accept, content-type Access-Control-Request-Method:POST Connection:keep-alive Host:localhost:8080 Origin:http://localhost:63343 Referer:http://localhost:63343/Project/index.html?uName=g&uPassword=g&uPasswordConfirm=g User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36 Query String Parametersview sourceview URL encoded password:g username:g Response Headersview source Allow:GET, HEAD, POST, PUT, DELETE, OPTIONS Content-Length:0 Date:Fri, 04 Apr 2014 09:50:35 GMT Server:Apache-Coyote/1.1
Update#4: Annotated the filter with @WebFilter instead of @Component, didn't help
Update#5: Here is my applicationContext.xml file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.robin"/> <mvc:annotation-driven/> <!-- Hibernate Session Factory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan"> <array> <value>com.robin.model</value> </array> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">create</prop> </props> </property> <property name="annotatedClasses"> <list> <value>com.robin.model.User</value> </list> </property> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!--Driver for mysqldb --> <import resource="mysql-context.xml"/> </beans>
I also added the code from my controller and register.html file here:
charmanderControllers.controller('registerController', ['$scope', 'register', function($scope, register){ $scope.username = ''; $scope.password = ''; $scope.register = function () { register.registerUser({'username': $scope.username, 'password': $scope.password}).$promise.then(function(data){ switch(data.response){ case true: //succes $scope.registered = true; $scope.userExists = false; break; case false: //user exists $scope.registered = false; $scope.userExists = true; break; } console.log(data.response); }) }; $scope.checkValidRegister = function (invalid) { console.log(invalid); console.log($scope.passwordConfirm); console.log($scope.password); console.log($scope.username); if (invalid || $scope.password != $scope.passwordConfirm) { console.log("I shouldnt be here"); $scope.validation = true; if ($scope.password != $scope.passwordConfirm) { $scope.passwordError = true; } } else { register(); } }; }]);
register.html
<h1>Register now!</h1> <form method="post" class="register" novalidate> <p> <label for="email">E-mail:</label> <input type="text" name="login" id="email" placeholder="E-mail address..." required ng-model="username"> </p> <p> <label for="password">Password:</label> <input type="password" name="password" id="password" placeholder="Password..." required ng-model="password"> </p> <p> <label for="confirm_password">Confirm password: </label> <input type="password" name="confirm_password" id="confirm_password" placeholder="Confirm password..." required ng-model="passwordConfirm"> <span ng-show="passwordError">Passwords do not match!</span> </p> <p class="register_submit"> <button type="submit" class="register-button" ng-click="checkValidRegister()">Register</button> </p> </form>
Your code and configuration looks good in general and I was able to run it on local environment. Please remove @Component annotation from your SimpleCORSFilter
, because you use it as a plain Servlet Filter and it doesn't need to be a part of Spring context.
UPD. Tomcat 7 has its own CORS filter implementation. You can check documentation and source code for more details. I have modified the headers to reflect its default configuration, should work as expected now.
Since you are already using Spring and if you are using Spring 4.2 or higher, you dont need CorsFilter
, but can simply annotate your controller method with CrossOrigin
. Here is the excellent article on this, worth a read.
Please also check nice resource which describes CORS configuration for different platforms.
Here is my working example using plain Filter implementation:
Controller:
@Controller public class UserController { private static Logger log = Logger.getAnonymousLogger(); @RequestMapping( value = "/register", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded") @ResponseBody public String register(@RequestParam(value = "user") String username, @RequestParam(value = "password") String password) { log.info(username + " " + password); return "true"; } }
Filter:
public class CorsFilter implements Filter { private static final Logger log = Logger.getAnonymousLogger(); @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("Adding Access Control Response Headers"); HttpServletResponse response = (HttpServletResponse) servletResponse; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, HEAD, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
Filter mapping in web.xml:
<filter> <filter-name>cors</filter-name> <filter-class>com.udalmik.filter.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>cors</filter-name> <url-pattern>/register</url-pattern> </filter-mapping>
JS to perform request from separate web app (JQuery):
$(document).ready(function() { $('#buttonId').click(function() { $.ajax({ type: "POST", url: "http://localhost:8080/register", success : function(data){ console.log(data); }, data : { user : '[email protected]', password : 'password' } }); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With