Cookie异常之:illegalArgumentException: An invalid character [32] was present in the Cookie value

当使用 Spring Session 存储 session 数据时,由于是依托 cookie 的,但是 tomcat 对 cookie 的解析又有所限制,所以出现了文中的问题。

一、问题描述

    项目是 spring boot 1.4版本的项目,出现了如下的错误:</p>

1
2
3
4
5
6
7
8
9
10
11
12
13
java.lang.IllegalArgumentException:&nbsp;An&nbsp;invalid&nbsp;character&nbsp;[32]&nbsp;was&nbsp;present&nbsp;in&nbsp;the&nbsp;Cookie&nbsp;value
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateCookieValue(Rfc6265CookieProcessor.java:160)&nbsp;~[tomcat-embed-core-8.5.4.jar:8.5.4]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:109)&nbsp;~[tomcat-embed-core-8.5.4.jar:8.5.4]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.catalina.connector.Response.generateCookieString(Response.java:989)&nbsp;~[tomcat-embed-core-8.5.4.jar:8.5.4]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.catalina.connector.Response.addCookie(Response.java:937)&nbsp;~[tomcat-embed-core-8.5.4.jar:8.5.4]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.java:386)&nbsp;~[tomcat-embed-core-8.5.4.jar:8.5.4]
...
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425)&nbsp;[tomcat-embed-core-8.5.4.jar:8.5.4]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)&nbsp;[tomcat-embed-core-8.5.4.jar:8.5.4]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)&nbsp;[na:1.8.0_101]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)&nbsp;[na:1.8.0_101]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)&nbsp;[tomcat-embed-core-8.5.4.jar:8.5.4]
&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;java.lang.Thread.run(Thread.java:745)&nbsp;[na:1.8.0_101]

    从问题中我们看出,是 cookie 的原因引起的问题,但是排查我们手动使用 cookie 的地方并没有发现任何问题。

    原来,是因为我们依托了 spring session 来存储一些数据,然而这些赋值的动作是 spring 底层自动完成的,我们并没有手动进行相关操作。




二、解决

    经查证,是因为 tomcat 的问题,项目中默认使用的是 tomcat8.5,而在 tomcat8.5 中的 cookie 处理默认更改为了 RFC 6265 兼容实现,该规则严格限制了 cookie 的 name 命名规范,即 name 中不允许出现空格(ACSII 32)、等号等字符,所以引起了上文的错误。

    但是这些动作是 spring session 操作的,我们不想进行相关的修改,并且考虑兼容的因素,我们改变角度,即对 Tomcat 进行处理,在本项目中(spring boot),只需要注册如下的 bean 即可。

1
2
3
4
5
6
7
8
9
@Bean
public&nbsp;EmbeddedServletContainerCustomizer&nbsp;customizer()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;container&nbsp;->&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(container&nbsp;instanceof&nbsp;TomcatEmbeddedServletContainerFactory)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TomcatEmbeddedServletContainerFactory&nbsp;tomcat&nbsp;=&nbsp;(TomcatEmbeddedServletContainerFactory)&nbsp;container;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tomcat.addContextCustomizers(context&nbsp;->&nbsp;context.setCookieProcessor(new&nbsp;LegacyCookieProcessor()));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;};
}


三、扩展

    

    其实,上文的处理方式是基于 spring boot 1.x 系列的,当使用 2.0 版本时,并不需要注册上文中的 bean,原因有两点:

        1、从 spring boot 2.0 开始,EmbeddedServletContainerCustomizer 已经被 WebServerFactoryCustomizer 所替代;

        2、从 spring boot 2.0 开始,session cookie 默认是 Base64 编码的,所以可以有效避免本文的问题。

    

    参考:stackoverflow.com





------ 本文结束 感谢阅读 ------
0%