CORS过滤器不能正常工作

时间:2021-11-03 02:17:06

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

我正在尝试将Webstorm应用程序的请求发送到我的后端应用程序,它们都在不同的端口上,我在前端使用angularJS,在后端使用java。我读了一些关于CORS过滤器的知识,我了解到,为了实现这些交叉源请求,我需要实现它们。然而,在这样做之后,我的错误,存在

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

更新:我尝试将过滤器实现为OncePerRequestFilter,但仍然无效。这里有人能帮我吗?

Update#2: Also tried this one, http://software.dzhuvinov.com/cors-filter-installation.html, no luck

更新#2:也试过这个,http://software.dzhuvinov.com/cors-filter-installation.html,运气不好

Update#3: This was my output in the console, I can see that the response did not add any headers:

更新#3:这是我在控制台的输出,我可以看到响应没有添加任何标题:

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

更新#4:用@WebFilter而不是@Component来注释过滤器,没有帮助

Update#5: Here is my applicationContext.xml file:

更新#5:这是我的应用程序上下文。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>

I also added the code from my controller and register.html file here:

我还添加了来自我的控制器和寄存器的代码。html文件:

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

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>

1 个解决方案

#1


31  

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.

您的代码和配置看起来很好,我可以在本地环境中运行它。请从SimpleCORSFilter中删除@Component注释,因为您将它用作普通的Servlet过滤器,它不需要是Spring上下文的一部分。

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.

乌利希期刊指南。Tomcat 7有自己的CORS过滤器实现。您可以查看文档和源代码,了解更多细节。我已经修改了头部以反映其默认配置,现在应该可以像预期的那样工作了。

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.

由于您已经在使用Spring,并且如果您正在使用Spring 4.2或更高版本,那么您不需要CorsFilter,只需使用CrossOrigin对控制器方法进行注释。这里有一篇很好的文章,值得一读。

Please also check nice resource which describes CORS configuration for different platforms.

还请检查nice资源,它描述了不同平台的CORS配置。

Here is my working example using plain Filter implementation:

下面是我使用plain Filter实现的工作示例:

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:

在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):

JS执行来自独立web应用程序(JQuery)的请求:

$(document).ready(function() {
    $('#buttonId').click(function() {
        $.ajax({
            type: "POST",
            url: "http://localhost:8080/register",
            success : function(data){
                console.log(data);
            },
            data : {
                user : 'test.user@acme.com',
                password : 'password'
            }
        });
    }
}

#1


31  

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.

您的代码和配置看起来很好,我可以在本地环境中运行它。请从SimpleCORSFilter中删除@Component注释,因为您将它用作普通的Servlet过滤器,它不需要是Spring上下文的一部分。

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.

乌利希期刊指南。Tomcat 7有自己的CORS过滤器实现。您可以查看文档和源代码,了解更多细节。我已经修改了头部以反映其默认配置,现在应该可以像预期的那样工作了。

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.

由于您已经在使用Spring,并且如果您正在使用Spring 4.2或更高版本,那么您不需要CorsFilter,只需使用CrossOrigin对控制器方法进行注释。这里有一篇很好的文章,值得一读。

Please also check nice resource which describes CORS configuration for different platforms.

还请检查nice资源,它描述了不同平台的CORS配置。

Here is my working example using plain Filter implementation:

下面是我使用plain Filter实现的工作示例:

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:

在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):

JS执行来自独立web应用程序(JQuery)的请求:

$(document).ready(function() {
    $('#buttonId').click(function() {
        $.ajax({
            type: "POST",
            url: "http://localhost:8080/register",
            success : function(data){
                console.log(data);
            },
            data : {
                user : 'test.user@acme.com',
                password : 'password'
            }
        });
    }
}