Java Spring WebRequest getParameter()显示为null

Java Spring WebRequest getParameter()显示为null,java,spring,model-view-controller,mailchimp,webhooks,Java,Spring,Model View Controller,Mailchimp,Webhooks,在托管Tomcat服务器中使用Spring MVC控制器处理Mailchimp Webhook请求时,我遇到了一个问题(在我自己的开发环境中,一切都很好) 我只是在webhook URL中添加了一个“secret”参数,如下所示: http://doamin/webhook.html?secret=password Mailchimp向webapp发出POST请求,但他们说出于安全原因,您应该向URL添加一个“秘密”密钥(因此获取参数) 然后,在进入业务逻辑之前,我只需检查该参数,通过 @Re

在托管Tomcat服务器中使用Spring MVC控制器处理Mailchimp Webhook请求时,我遇到了一个问题(在我自己的开发环境中,一切都很好)

我只是在webhook URL中添加了一个“secret”参数,如下所示:

http://doamin/webhook.html?secret=password
Mailchimp向webapp发出POST请求,但他们说出于安全原因,您应该向URL添加一个“秘密”密钥(因此获取参数)

然后,在进入业务逻辑之前,我只需检查该参数,通过

@RequestMapping(method=RequestMethod.POST)
public ModelAndView postProcess(WebRequest request){
    if (request.getParameter("secret").equals("password"){
        //business logic
    }
}
这在我本地的tomcat中是可以的。参数正确地从Mailchimp请求中获取,并且所有业务逻辑都运行。

但随后我将WAR上传到生产环境中,我可以看到那里没有运行业务逻辑

经过大量有趣的调试。。。我发现getParameter(“secret”)返回null

你认为这可能和tomcat有关吗

我的本地tomcat版本是7.0.67

我的托管tomcat是7.0.62版

My web.xml看起来像:

<web-app 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_0.xsd"
    version="3.0">
    <display-name>Servlet 3.0 Web Application</display-name>

  <display-name>Spring Web MVC Application</display-name>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

    <!--  Load up all spring xml files as part of the loading of the webapp -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/security-config.xml;/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    </context-param>

     <!--  This filter is used by Spring Security to intercept all URL patterns -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <error-page>
        <error-code>403</error-code>
        <location>/Forbidden.html</location>
    </error-page>

    <error-page>
      <exception-type>org.springframework.web.util.NestedServletException</exception-type>
      <location>/JDBCException.html</location>
    </error-page>   

    <!-- Session expiration max time (in minutes) -->
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

</web-app>
<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE server-xml [
  <!ENTITY jelastic-ssl SYSTEM "jelastic-ssl.xml">
  <!ENTITY jelastic-ha SYSTEM "jelastic-ha.xml">
]>

<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!-- Note:  A "Server" is not itself a "Container", so you may not
     define subcomponents such as "Valves" at this level.
     Documentation at /docs/config/server.html
 -->
<Server port="8005" shutdown="SHUTDOWN">
  <!-- Security listener. Documentation at /docs/config/listeners.html
  <Listener className="org.apache.catalina.security.SecurityListener" />
  -->
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <!-- A "Service" is a collection of one or more "Connectors" that share
       a single "Container" Note:  A "Service" is not itself a "Container",
       so you may not define subcomponents such as "Valves" at this level.
       Documentation at /docs/config/service.html
   -->
  <Service name="Catalina">

    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->


    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL HTTP/1.1 Connector on port 8080
    -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="443" />

    <!--############## SSL Connector for _domain_name ### PROTO_Dl231aIDsW4 ##########-->
    &jelastic-ssl;
    <!--############## SSL Connector for _domain_name ### PROTO_Dl541aINsMx ##########-->
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    -->
    <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the JSSE configuration, when using APR, the
         connector should be using the OpenSSL style configuration
         described in the APR documentation -->
    <!--
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
    -->

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />


    <!-- An Engine represents the entry point (within Catalina) that processes
         every request.  The Engine implementation for Tomcat stand alone
         analyzes the HTTP headers included with the request, and passes them
         on to the appropriate Host (virtual host).
         Documentation at /docs/config/engine.html -->

    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="${jvmRid}">
    -->
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="${jvmRid}">

    <!--Jelastic HA clusteting is enabled here so please do not remove this line untill you reasly know what you are doing -->
    &jelastic-ha;
    <!-- Use the LockOutRealm to prevent attempts to guess user passwords
           via a brute-force attack -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>
2) 控制器,创建线程并回答Mailchimp请求:

package es.edm.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;

import es.edm.services.MailingListService;
import es.edm.util.MailingListRequestProcessor;

@Controller
@RequestMapping(path="/Webhook")
public class MailingServiceIntegrationController_MailchimpImpl {

    @Autowired
    MailingListService mailing;

    @RequestMapping(method=RequestMethod.GET)
    public ModelAndView getProcess(WebRequest request){
        return new ModelAndView("/web/MailchimpAnswer.jsp");
    }

    @RequestMapping(method=RequestMethod.POST)
    public ModelAndView postProcess(WebRequest request){
        MailingListRequestProcessor processor = new MailingListRequestProcessor();
        processor.start(request, mailing);
        return new ModelAndView("/web/MailchimpAnswer.jsp");
    }
}
3) 以及用于实现业务逻辑的服务类:

package es.edm.util;

import java.util.Date;

import org.springframework.web.context.request.WebRequest;

import es.edm.services.MailingListService;

public class MailingListRequestProcessor implements Runnable {

    private Thread t;
    private WebRequest request;
    private MailingListService mailing;

    @Override
    public void run() {
        System.out.println(new Date() + ": Request status afet calling the thread to start, but before calling business logic" + request);
        mailing.processRequest(request);
    }

    public void start (WebRequest request, MailingListService mailing) {
        if (t == null){
            System.out.println(new Date() + ": Request status before calling the thread to start" + request);
            this.request = request;
            this.mailing = mailing;
            t = new Thread (this, "MailchimpRequest");
            t.start ();
        }
    }
}
@Override
public void processRequest(WebRequest request) {
    //To recover, once solved the problem with Jelastic and getParameters();
    //if (request.getParameter("secret")!= null){
        //if (request.getParameter("secret").equals(conf.getMailingListSecretPassword())){
            switch (request.getParameter("type")){
            case "subscribe": processSubscribe(request); break;
            case "unsubscribe": processUnsubscribe(request); break;
            case "profile": processProfile(request); break;
            case "upemail": processEmailChange(request); break;
            case "cleaned": processCleanedEmail(request); break;
            case "campaign": processCampaign(request); break;
            }
        //}
    //}
}
catalina的输出如下:

Exception in thread "MailchimpRequest" java.lang.NullPointerException
    at es.edm.services.Impl.MailingListService_Mailchimp_Impl.processRequest(MailingListService_Mailchimp_Impl.java:37)
    at es.edm.util.MailingListRequestProcessor.run(MailingListRequestProcessor.java:15)
    at java.lang.Thread.run(Thread.java:745)
MailingListService\u Mailchimp\u Impl.java:37这是:

switch (request.getParameter("type")){
request.getParameter(“类型”)为空。。。而在我的本地tomcat是正确填写的


谢谢

在使用Jelastic时,请尝试获得Jelastic支持。我想他们可以帮你解决这个问题。

经过长时间的研究,我最终发现了问题:

<!-- This should be removed to improve security!!!! -->
<csrf disabled="true"/>


在使用Mailchimp时,您不能使用CSRF保护,因为它需要将“secret”参数作为GET参数传递,但CSRF可以阻止它。

谢谢,Intellio。现在问题解决了:这是一个问题: