web-dev-qa-db-ja.com

CORSフィルターが意図したとおりに機能しない

Webstormアプリケーションからバックエンドアプリケーションにリクエストを送信しようとしています。どちらも異なるポートにあります。フロントエンドでangleJSを使用し、バックエンドで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.

私は何か間違ったことをしたと信じるようになったまったく変わっていませんでした、ここに私がリクエストを送信しているコードがあります:

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

    }
]);

私のcorsFilterは次のように書かれています:

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

これは私の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>

これは私がリクエストをキャッチしているコントローラーです:

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

更新:フィルターをOncePerRequestFilterとして実装しようとしましたが、まだ機能しません。ここでさらに助けてくれる人はいますか?

Update#2:これも試してみました http://software.dzhuvinov.com/cors-filter-installation.html 、運がありません

Update#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:@Componentの代わりに@WebFilterでフィルターに注釈を付けましたが、助けにはなりませんでした

Update#5:これは、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>

また、コントローラーとregister.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

 <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

あなたのコードと設定は一般的に見栄えが良く、ローカル環境で実行できました。 SimpleCORSFilterから@ Componentアノテーションを削除してください。これはプレーンなサーブレットフィルターとして使用する必要があり、 Springコンテキストの一部。

UPD。Tomcat 7には独自の CORSフィルター実装 があります。詳細については、ドキュメントとソースコードを確認してください。デフォルトの構成を反映するようにヘッダーを変更しましたが、期待どおりに動作するはずです。

すでにSpringを使用しており、Spring 4.2以降を使用している場合、CorsFilterは不要ですが、コントローラーメソッドに CrossOrigin で簡単に注釈を付けることができます。これは 優秀な記事 で、読む価値があります。

異なるプラットフォームのCORS設定 を説明するNiceリソースも確認してください。

これは、単純なFilter実装を使用した私の実例です。

コントローラ:

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

}

フィルタ:

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

    }
}

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>

別のWebアプリ(JQuery)からリクエストを実行するJS:

$(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