一、问题描述
项目是 spring boot 1.4版本的项目,出现了如下的错误:java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value at org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateCookieValue(Rfc6265CookieProcessor.java:160) ~[tomcat-embed-core-8.5.4.jar:8.5.4] at org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:109) ~[tomcat-embed-core-8.5.4.jar:8.5.4] at org.apache.catalina.connector.Response.generateCookieString(Response.java:989) ~[tomcat-embed-core-8.5.4.jar:8.5.4] at org.apache.catalina.connector.Response.addCookie(Response.java:937) ~[tomcat-embed-core-8.5.4.jar:8.5.4] at org.apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.java:386) ~[tomcat-embed-core-8.5.4.jar:8.5.4] ... at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425) [tomcat-embed-core-8.5.4.jar:8.5.4] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.4.jar:8.5.4] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_101] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_101] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.4.jar:8.5.4] at java.lang.Thread.run(Thread.java:745) [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 即可。@Bean public EmbeddedServletContainerCustomizer customizer() { return container -> { if (container instanceof TomcatEmbeddedServletContainerFactory) { TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container; tomcat.addContextCustomizers(context -> context.setCookieProcessor(new LegacyCookieProcessor())); } }; }
三、扩展
其实,上文的处理方式是基于 spring boot 1.x 系列的,当使用 2.0 版本时,并不需要注册上文中的 bean,原因有两点:
1、从 spring boot 2.0 开始,EmbeddedServletContainerCustomizer 已经被 WebServerFactoryCustomizer 所替代; 2、从 spring boot 2.0 开始,session cookie 默认是 Base64 编码的,所以可以有效避免本文的问题。
参考:stackoverflow.com
文章评论