在我的JSF页面(Primefaces)上,googlebot在访问网站时引发ViewExpiredException。它只发生在POST请求上(无效的javax.faces.ViewState?)。
我正在运行Wildfly 9.0.1.Final,Primefaces 5.3
我的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Production</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
<param-value>0</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.defaultResourceMaxAge</param-name>
<param-value>3628800000</param-value>
</context-param>
<context-param>
<param-name>primefaces.SUBMIT</param-name>
<param-value>partial</param-value>
</context-param>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>bootstrap</param-value>
</context-param>
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>native</param-value>
</context-param>
<context-param>
<param-name>org.primefaces.extensions.DELIVER_UNCOMPRESSED_RESOURCES</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.primefaces.extensions.WRAP_PRIME_FACES_RESOURCES</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>org.ocpsoft.rewrite.annotation.BASE_PACKAGES</param-name>
<param-value>pl.izen.carmen.rewrite</param-value>
</context-param>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
<init-param>
<param-name>thresholdSize</param-name>
<param-value>51200</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<listener>
<listener-class>org.ocpsoft.rewrite.servlet.impl.RewriteServletRequestListener</listener-class>
</listener>
<listener>
<listener-class>org.ocpsoft.rewrite.servlet.impl.RewriteServletContextListener</listener-class>
</listener>
<filter>
<filter-name>OCPsoft Rewrite Filter</filter-name>
<filter-class>pl.izen.carmen.custom.servlet.IzenRewriteFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>OCPsoft Rewrite Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ASYNC</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>Public Images Servlet</servlet-name>
<servlet-class>pl.izen.carmen.servlets.images.PublicImagesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Public Images Servlet</servlet-name>
<url-pattern>/public_images/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Product Images Servlet</servlet-name>
<servlet-class>pl.izen.carmen.servlets.images.ProductsImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Product Images Servlet</servlet-name>
<url-pattern>/product/image/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>CKEditorUploadServlet</servlet-name>
<servlet-class>pl.izen.carmen.servlets.images.CKEditorUploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CKEditorUploadServlet</servlet-name>
<url-pattern>/ckeditor/upload/uploadimage</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>PrimePushServlet</servlet-name>
<servlet-class>org.primefaces.push.PushServlet</servlet-class>
<init-param>
<param-name>org.atmosphere.cpr.broadcasterCacheClass</param-name>
<param-value>org.atmosphere.cache.UUIDBroadcasterCache</param-value>
</init-param>
<init-param>
<param-name>org.atmosphere.annotation.packages</param-name>
<param-value>org.primefaces.push</param-value>
</init-param>
<init-param>
<param-name>org.atmosphere.cpr.packages</param-name>
<param-value>pl.izen.push</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>PrimePushServlet</servlet-name>
<url-pattern>/primepush/*</url-pattern>
</servlet-mapping>
<!--
<servlet>
<servlet-name>RESTEasy JSAPI</servlet-name>
<servlet-class>org.jboss.resteasy.jsapi.JSAPIServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RESTEasy JSAPI</servlet-name>
<url-pattern>/rest-js</url-pattern>
</servlet-mapping>
-->
<servlet-mapping>
<servlet-name>CeneoServlet</servlet-name>
<url-pattern>/ceneo/servlet/*</url-pattern>
</servlet-mapping>
<servlet>
<display-name>CeneoServlet</display-name>
<servlet-name>CeneoServlet</servlet-name>
<servlet-class>pl.izen.carmen.custom.integration.ceneo.CeneoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HeurekaServlet</servlet-name>
<url-pattern>/heureka/*</url-pattern>
</servlet-mapping>
<servlet>
<display-name>HeurekaServlet</display-name>
<servlet-name>HeurekaServlet</servlet-name>
<servlet-class>pl.izen.carmen.custom.integration.heureka.HeurekaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MerchantServlet</servlet-name>
<url-pattern>/merchant/servlet/*</url-pattern>
</servlet-mapping>
<servlet>
<display-name>MerchantServlet</display-name>
<servlet-name>MerchantServlet</servlet-name>
<servlet-class>pl.izen.carmen.custom.integration.google.GoogleMerchantServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>SitemapXmlServlet</servlet-name>
<servlet-class>pl.izen.carmen.custom.servlet.SitemapXmlServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SitemapXmlServlet</servlet-name>
<url-pattern>/sitemap.xml</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>RobotsTxtServlet</servlet-name>
<servlet-class>pl.izen.carmen.custom.servlet.RobotsTxtServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>RobotsTxtServlet</servlet-name>
<url-pattern>/robots.txt</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>start.xhtml</welcome-file>
</welcome-file-list>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>administrator</role-name>
</security-role>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/loginError.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>CSS</web-resource-name>
<url-pattern>/javax.faces.resource/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>CSS</web-resource-name>
<url-pattern>/resources/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>SitemapXmlServlet</web-resource-name>
<url-pattern>/sitemap.xml</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>RobotsTxtServlet</web-resource-name>
<url-pattern>/robots.txt</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Unsecured application frontend - object page</web-resource-name>
<description>Objects</description>
<url-pattern>/pages/seoObject.xhtml</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>login.xhtml</web-resource-name>
<description>Unprotect login.xhtml</description>
<url-pattern>/login.xhtml</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Public resources</web-resource-name>
<description>All visible resources</description>
<url-pattern>*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>All resources</web-resource-name>
<description>Protects all resources</description>
<url-pattern>/pages/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>administrator</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>All resources</web-resource-name>
<description>Protects all resources</description>
<url-pattern>/admin</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>administrator</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>All resources</web-resource-name>
<description>Protects all resources</description>
<url-pattern>/index.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>administrator</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Public Images Servlet</web-resource-name>
<url-pattern>/public_images/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Unsecured application frontend</web-resource-name>
<description>Start page</description>
<url-pattern>/start.xhtml</url-pattern>
</web-resource-collection>
</security-constraint>
<session-config>
<session-timeout>60</session-timeout>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
<error-page>
<error-code>500</error-code>
<location>/error/error_500.xhtml</location>
</error-page>
<error-page>
<error-code>408</error-code>
<location>/error/error_408.xhtml</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/error/error_404.xhtml</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error/error_404.xhtml</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error/error.xhtml</location>
</error-page>
<security-constraint>
<web-resource-collection>
<web-resource-name>secure</web-resource-name>
<url-pattern>/secure/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>administrator</role-name>
</auth-constraint>
</security-constraint>
<mime-mapping>
<extension>ico</extension>
<mime-type>image/x-icon</mime-type>
</mime-mapping>
</web-app>
我使用的几乎所有组件都是@ViewScoped(CDI),我没有使用@ConversationScoped组件。正如您在web.xml中看到的,我还使用了带有primepush的重写过滤器(两者都运行得很好)。
导致错误的请求:
X-FORWARDED-FROM: 66.249.79.135
METHOD: POST
PARAM: viewUrl => some_product_name
PARAM: commands:j_idt55 => commands:j_idt55
PARAM: javax.faces.ViewState => 1802363348692608902:3687015195185271050
PARAM: width => 1024
PARAM: javax.faces.source => commands:j_idt55
PARAM: javax.faces.partial.ajax => true
PARAM: javax.faces.partial.execute => @all
PARAM: commands => commands
PARAM: height => 1024
编辑:它主要发生在一个页面上,该页面使用额外的参数(viewUrl)来决定将显示什么产品。这是一个GET参数,但谷歌机器人使用POST方法。在这个页面上,用户可以将产品添加到购物车或对其进行评分,而无需其他操作。
来自爬网程序(谷歌)的GET请求运行良好。
第2版:我观察到,我在进行POST导航时遇到了同样的异常(faces redirect=true),但当我将com.sun.faces.numberOfLogicalViews更改为100时,不再抛出异常。JSF为什么要构建这么多视图?
如有任何帮助,我们将不胜感激。
过了很长时间,我找到了原因。谷歌机器人是一个缓存网站,从一段时间以来,它有可能在缓存网站上发布请求。它似乎用旧的JSF ViewId启动了primefaces远程命令。这就是问题所在。