美文网首页
SpringBoot项目中添加cookie报错问题

SpringBoot项目中添加cookie报错问题

作者: 从零开始的程序猿生活 | 来源:发表于2022-09-26 11:10 被阅读0次
    添加cookie
                            // 设置登录状态cookie
                            Cookie cookie = new Cookie("loginStatus",JSON.toJSONString(loginStatus));
                            cookie.setMaxAge(minutes * 60);
                            cookie.setDomain("cnki.net");
                            cookie.setPath("/");
                            response.addCookie(cookie);
    
    报下面错误

    java.lang.IllegalArgumentException: An invalid character [34] was present in the Cookie value

    查询ASCII码表发现34 对应的为 " 双引号,但是之前C#项目中添加同样的cookie是没问题的。

    原因

    跟踪源码发现问题出现在生成cookie的header字符串上


    0CIRUU2`ZNNKH24MO4S{5ZB.png

    进入源码发现是因为tomcat8.5以后 cookie的处理器由LegacyCookieProcessor 更改为了Rfc6265CookieProcessor

    1.png

    而在Rfc6265CookieProcessor中增加了对空格,双银号等特殊字符的校验


    2.png

    校验的代码为:

        private void validateCookieValue(String value) {
            int start = 0;
            int end = value.length();
    
            if (end > 1 && value.charAt(0) == '"' && value.charAt(end - 1) == '"') {
                start = 1;
                end--;
            }
    
            char[] chars = value.toCharArray();
            for (int i = start; i < end; i++) {
                char c = chars[i];
                if (c < 0x21 || c == 0x22 || c == 0x2c || c == 0x3b || c == 0x5c || c == 0x7f) {
                    throw new IllegalArgumentException(sm.getString(
                            "rfc6265CookieProcessor.invalidCharInValue", Integer.toString(c)));
                }
            }
        }
    
    解决办法

    1、降低tomcat版本
    2、在tomcat中更改cookie处理器
    3、重写generateHeader方法,去掉校验部分
    新建CookieUtils工具类

    
    import org.apache.tomcat.util.http.CookieProcessorBase;
    import org.apache.tomcat.util.http.MimeHeaders;
    import org.apache.tomcat.util.http.SameSiteCookies;
    import org.apache.tomcat.util.http.ServerCookies;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import java.nio.charset.Charset;
    import java.text.FieldPosition;
    import java.util.Date;
    
    @Component
    public class CookieUtils extends CookieProcessorBase {
    
        @Override
        public void parseCookieHeader(MimeHeaders headers, ServerCookies serverCookies) {
    
        }
    
        @Override
        public String generateHeader(Cookie cookie) {
            return null;
        }
    
        @Override
        public String generateHeader(Cookie cookie, HttpServletRequest request) {
            // Can't use StringBuilder due to DateFormat
            StringBuffer header = new StringBuffer();
    
            // TODO: Name validation takes place in Cookie and cannot be configured
            //       per Context. Moving it to here would allow per Context config
            //       but delay validation until the header is generated. However,
            //       the spec requires an IllegalArgumentException on Cookie
            //       generation.
            header.append(cookie.getName());
            header.append('=');
            String value = cookie.getValue();
            if (value != null && value.length() > 0) {
                header.append(value);
            }
    
            // RFC 6265 prefers Max-Age to Expires but... (see below)
            int maxAge = cookie.getMaxAge();
            if (maxAge > -1) {
                // Negative Max-Age is equivalent to no Max-Age
                header.append("; Max-Age=");
                header.append(maxAge);
    
                // Microsoft IE and Microsoft Edge don't understand Max-Age so send
                // expires as well. Without this, persistent cookies fail with those
                // browsers. See http://tomcat.markmail.org/thread/g6sipbofsjossacn
    
                // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
                header.append ("; Expires=");
                // To expire immediately we need to set the time in past
                if (maxAge == 0) {
                    header.append(ANCIENT_DATE);
                } else {
                    COOKIE_DATE_FORMAT.get().format(
                            new Date(System.currentTimeMillis() + maxAge * 1000L),
                            header,
                            new FieldPosition(0));
                }
            }
    
            String domain = cookie.getDomain();
            if (domain != null && domain.length() > 0) {
                header.append("; Domain=");
                header.append(domain);
            }
    
            String path = cookie.getPath();
            if (path != null && path.length() > 0) {
                header.append("; Path=");
                header.append(path);
            }
    
            if (cookie.getSecure()) {
                header.append("; Secure");
            }
    
            if (cookie.isHttpOnly()) {
                header.append("; HttpOnly");
            }
    
            SameSiteCookies sameSiteCookiesValue = getSameSiteCookies();
    
            if (!sameSiteCookiesValue.equals(SameSiteCookies.UNSET)) {
                header.append("; SameSite=");
                header.append(sameSiteCookiesValue.getValue());
            }
    
            return header.toString();
        }
    
        @Override
        public Charset getCharset() {
            return null;
        }
    }
    
    

    添加cookie时自己写入set-cookie

                            // 设置登录状态cookie
                            Cookie cookie = new Cookie("loginStatus",JSON.toJSONString(loginStatus));
                            cookie.setMaxAge(minutes * 60);
                            cookie.setDomain("cnki.net");
                            cookie.setPath("/");
                            String cookieStr = cookieUtils.generateHeader(cookie, request);
                            response.addHeader("set-cookie",cookieStr);
    

    相关文章

      网友评论

          本文标题:SpringBoot项目中添加cookie报错问题

          本文链接:https://www.haomeiwen.com/subject/lkwtartx.html