java.lang.IllegalArgumentException: An invalid domain [.test.com] was specified for this cookie

本文探讨了在Tomcat 8.0与8.5版本间,由于CookieProcessor实现不同导致的单点登录功能问题。主要分析了org.apache.tomcat.util.http.LegacyCookieProcessor与org.apache.tomcat.util.http.Rfc6265CookieProcessor的区别,并提供了两种解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当项目中使用单点登录功能时,通常会使用cookie进行信息的保存,这样就可以在多个子域名上存取用户信息。
比如有三个domain分别为test.com,cml.test.com,b.test.com这三个域名下的cookie是需要互相访问的。这时会在response上写入cookie信息

        Cookie cookie = new Cookie("testCookie", "test");
        cookie.setDomain(".test.com");
        cookie.setPath("/");
        cookie.setMaxAge(36000);
        resp.addCookie(cookie);

这样写在tomcat8.0上是没问题的,三个域名可以共享cookie信息。但是把它放到tomcat8.5上就报错了

java.lang.IllegalArgumentException: An invalid domain [.test.com] was specified for this cookie
        at org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateDomain(Rfc6265CookieProcessor.java:181)
        at org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:123)
        at org.apache.catalina.connector.Response.generateCookieString(Response.java:989)
        at org.apache.catalina.connector.Response.addCookie(Response.java:937)
        at org.apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.java:386)
        at com.cml.mvc.controller.HelloWorld.str(HelloWorld.java:98)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)

在tomcat8.5上是使用org.apache.tomcat.util.http.Rfc6265CookieProcessor

The standard implementation of CookieProcessor is org.apache.tomcat.util.http.Rfc6265CookieProcessor.

This cookie processor is based on RFC6265 with the following changes to support better interoperability:

Values 0x80 to 0xFF are permitted in cookie-octet to support the use of UTF-8 in cookie values as used by HTML 5.
For cookies without a value, the '=' is not required after the name as some browsers do not sent it.
The RFC 6265 cookie processor is generally more lenient than the legacy cookie parser. In particular:

The '=' and '/' characters are always permitted in a cookie value.
Name only cookies are always permitted.
The cookie header is always preserved.
No additional attributes are supported by the RFC 6265 Cookie Processor.

文档地址

在tomcat8.0上使用的是org.apache.tomcat.util.http.LegacyCookieProcessor

The standard implementation of CookieProcessor is org.apache.tomcat.util.http.LegacyCookieProcessor. Note that it is anticipated that this will change to org.apache.tomcat.util.http.Rfc6265CookieProcessor in a future Tomcat 8 release.

This is the legacy cookie parser based on RFC6265, RFC2109 and RFC2616. It implements a strict interpretation of the cookie specifications. Due to various interoperability issues with browsers not all strict behaviours are enabled by default and additional options are available to further relax the behaviour of this cookie processor if required.

文档地址

问题就可以定位在CookieProcessor不同实现引起的。
原因分析见下半篇博客:An invalid domain [.test.com] was specified for this cookie 原因分析


解决方法:

  1. 指定完整的domain信息,但是这样单点登录就会有问题了
        Cookie cookie = new Cookie("testCookie", "test");
        cookie.setDomain("cml.test.com");
        cookie.setPath("/");
        cookie.setMaxAge(36000);
        resp.addCookie(cookie);

2.设置为一级域名(推荐)

        Cookie cookie = new Cookie("testCookie", "test");
        cookie.setDomain("test.com");
        cookie.setPath("/");
        cookie.setMaxAge(36000);
        resp.addCookie(cookie);

域名问题参考文章:顶级域名和二级域名共享cookie及相互删除cookie

### 问题分析与解决方法 在 Java 编程中,`java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String` 是一种常见的运行时异常。这种异常通常发生在尝试对 `java.util.Date` 和 `java.lang.String` 类型进行比较时[^1]。具体来说,当 SQL 查询条件中包含对日期字段的字符串判断逻辑(例如 `createTime = &#39; &#39;`),而实际传递的参数是 `Date` 类型时,就会引发此异常[^2]。 为了解决这一问题,需要确保在代码中正确处理类型转换,并避免直接对不同类型的对象进行比较。以下是具体的解决方案: --- ### 解决方案 #### 1. 修改 XML 或 SQL 条件逻辑 如果问题出现在 MyBatis 的 XML 配置文件中,可以通过调整 `<if>` 标签的条件逻辑来避免类型不匹配的问题。例如,将以下代码: ```xml <if test="deadline != null and deadline != &#39;&#39;"> deadline = #{deadline}, </if> ``` 修改为仅检查 `deadline` 是否为 `null`,而不进行字符串比较: ```xml <if test="deadline != null"> deadline = #{deadline}, </if> ``` 这样可以有效避免 `java.util.Date` 和 `java.lang.String` 的类型冲突[^3]。 --- #### 2. 确保参数类型一致性 在传递参数到 SQL 查询之前,应确保所有参数的类型一致。例如,如果数据库中的字段是 `DATE` 类型,则应该传递 `java.util.Date` 或其子类(如 `java.sql.Date`)作为参数,而不是传递字符串。 可以在代码中显式地进行类型转换,例如使用 `SimpleDateFormat` 将字符串转换为日期: ```java import java.text.SimpleDateFormat; import java.util.Date; public class DateConverter { public static Date convertToDate(String dateString) throws Exception { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); return dateFormat.parse(dateString); } } ``` 然后,在调用 SQL 查询之前,先将字符串参数转换为 `Date` 类型: ```java try { String deadlineStr = "2023-10-01"; Date deadlineDate = DateConverter.convertToDate(deadlineStr); // 将 deadlineDate 作为参数传递给 SQL 查询 } catch (Exception e) { e.printStackTrace(); } ``` --- #### 3. 使用 MyBatis 的类型处理器 MyBatis 提供了类型处理器(TypeHandler)机制,用于在 Java 对象和数据库字段之间进行类型转换。可以通过自定义类型处理器来确保 `java.util.Date` 和 `String` 之间的正确转换。 例如,定义一个自定义的类型处理器: ```java import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.Date; public class DateStringTypeHandler extends BaseTypeHandler<Date> { private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); @Override public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, DATE_FORMAT.format(parameter)); } @Override public Date getNullableResult(ResultSet rs, String columnName) throws SQLException { String dateStr = rs.getString(columnName); return dateStr == null ? null : parseDate(dateStr); } @Override public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String dateStr = rs.getString(columnIndex); return dateStr == null ? null : parseDate(dateStr); } @Override public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String dateStr = cs.getString(columnIndex); return dateStr == null ? null : parseDate(dateStr); } private Date parseDate(String dateStr) { try { return DATE_FORMAT.parse(dateStr); } catch (Exception e) { throw new RuntimeException("Failed to parse date string: " + dateStr, e); } } } ``` 接着,在 MyBatis 的配置文件中注册该类型处理器: ```xml <typeHandlers> <typeHandler handler="com.example.DateStringTypeHandler" javaType="java.util.Date" jdbcType="VARCHAR"/> </typeHandlers> ``` --- ### 总结 通过上述方法,可以有效解决 `java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String` 的问题。核心在于确保参数类型的一致性,并避免在代码或 SQL 中直接对不同类型的对象进行比较。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值