web-dev-qa-db-fra.com

Le filtre CORS ne fonctionne pas comme prévu

J'essaie d'envoyer une demande de mon application Webstorm à mon application d'arrière-plan, qui sont toutes deux sur des ports différents, je travaille avec angularJS à l'avant et Java en arrière-plan. J'ai lu un peu sur les filtres CORS et j’ai appris que pour faire des requêtes d’origine croisée, j’ai besoin de les implémenter. Cependant, après cela, mon erreur, étant

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.

n'a pas changé du tout ce qui m'a fait croire que j'avais fait quelque chose de mal, voici le code à partir duquel j'envoie la demande:

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'}
        });

    }
]);

Mon corsFilter est écrit comme ceci:

@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() {}
}

Voici mon 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>

C'est le contrôleur où j'attrape la demande:

@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);
    }
}

Mise à jour: j'ai essayé d'implémenter le filtre en tant que OncePerRequestFilter, cela ne fonctionne toujours pas. Quelqu'un peut-il m'aider davantage ici?

Mise à jour # 2: également essayé celui-ci, http://software.dzhuvinov.com/cors-filter-installation.html , pas de chance

Mise à jour # 3: C'était ma sortie dans la console, je peux voir que la réponse n'a ajouté aucun en-tête:

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

Mise à jour # 4: annoté le filtre avec @WebFilter au lieu de @Component, n'a pas aidé

Mise à jour # 5: Voici mon fichier applicationContext.xml:

<?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>

J'ai également ajouté le code de mon contrôleur et le fichier register.html ici:

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>
29
Robin-Hoodie

Votre code et votre configuration semblent bons en général et j'ai pu l'exécuter sur un environnement local. Veuillez supprimer @ Component l'annotation de votre SimpleCORSFilter, car vous l'utilisez comme un simple filtre de servlet et il n'est pas nécessaire que ce soit un partie du contexte de printemps.

UPD. Tomcat 7 a sa propre implémentation du filtre CORS . Vous pouvez consulter la documentation et le code source pour plus de détails. J'ai modifié les en-têtes pour refléter sa configuration par défaut, devrait fonctionner comme prévu maintenant.

Puisque vous utilisez déjà Spring et si vous utilisez Spring 4.2 ou supérieur, vous n'avez pas besoin de CorsFilter, mais pouvez simplement annoter votre méthode de contrôleur avec CrossOrigin . Voici le excellent article à ce sujet, mérite d'être lu.

Veuillez également vérifier la ressource Nice qui décrit configuration CORS pour différentes plates-formes .

Voici mon exemple de travail utilisant une implémentation de filtre simple:

Manette:

@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";
    }

}

Filtre:

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() {

    }
}

Mappage de filtre dans 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 pour effectuer une demande à partir d'une application Web distincte (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'
            }
        });
    }
}
33
udalmik