我发现我认为可能是 Spring 类 HttpHeadersReadOnlyHttpHeaders 中的一个错误。我想在用 Spring 提出 Jira 缺陷之前确认这一点。这是我用来创建空的 HttpHeaders 对象的代码片段:

HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY);

然后我使用以下方法将标题添加到我的新对象中:
myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip")

此后 HttpHeaders.EMPTY 不再为空
HttpHeaders.EMPTY.size() == 1

HttpHeaders.EMPTY 的 javadoc 指出:



这里的问题是,当在别处使用 'HttpHeaders.EMPTY' 时,它会引入意想不到的 header 。

考虑以下单元测试:
@Test
public void testUpdateEmptyHeaders() {
    assertEquals(0, HttpHeaders.EMPTY.size()); // **Success**
    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY);
    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
    assertEquals(0, HttpHeaders.EMPTY.size()); // **Assert Fails**
}

@Test
// This test will fail if run after the test above, but will be successful if run by itself
public void testEmptyHeaders() {
    assertEquals(0, HttpHeaders.EMPTY.size());
}

下面是单元测试的结果:
// testUpdateEmptyHeaders
08:39:28.450 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@2e222612, testMethod = testUpdateEmptyHeaders@AuditContextTest, testException = java.lang.AssertionError: expected:<0> but was:<1>

java.lang.AssertionError:
Expected :0
Actual   :1

// testEmptyHeaders
08:39:28.482 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@2e222612, testMethod = testEmptyHeaders@AuditContextTest, testException = java.lang.AssertionError: expected:<0> but was:<1>

java.lang.AssertionError:
Expected :0
Actual   :1

我觉得这是一个错误,因为 HttpHeaders.EMPTY 应该是不可变的。
我还能够通过在 Spring HttpHeaders.javaReadOnlyHttpHeaders.java 中进行两项更改来解决此问题

最佳答案

是的,你说得对,这可能是 spring 框架 HttpHeaders 的错误

public static final HttpHeaders EMPTY


案例:1
我们来看看 HttpHeaders.Empty ,它返回不可变对象(immutable对象)
    HttpHeaders head = HttpHeaders.EMPTY;

    System.out.println(System.identityHashCode(head));  //1338668845

    System.out.println(head.size());                    //0

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY);

    System.out.println(System.identityHashCode(myHeaders));  //159413332

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");

    head = HttpHeaders.EMPTY;
    System.out.println(System.identityHashCode(head));       //1338668845
    System.out.println(head.size());                    //1
    System.out.println(head);                            //{Accept-Encoding=[gzip]}

    HttpHeaders head1 = HttpHeaders.EMPTY;
    System.out.println(head1);                          //{Accept-Encoding=[gzip]}
    System.out.println(System.identityHashCode(head1));   //1338668845
结论:

案例:2 返回对象从 writableHttpHeaders 反射(reflect)到 HttpHeaders.EMPTY 单例对象(内部和间接)
    HttpHeaders head = HttpHeaders.EMPTY;

    System.out.println(System.identityHashCode(head));  //1338668845

    System.out.println(head.size());                //0

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY);

    System.out.println(System.identityHashCode(myHeaders));  //159413332

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");

    myHeaders.add("hello", "value");

    head = HttpHeaders.EMPTY;
    System.out.println(System.identityHashCode(head));  //1338668845
    System.out.println(head.size());              //2
    System.out.println(head);                     //{Accept-Encoding=[gzip], hello=[value]}

    HttpHeaders head1 = HttpHeaders.EMPTY;
    System.out.println(head1);                    //{Accept-Encoding=[gzip], hello=[value]}
    System.out.println(System.identityHashCode(head1));   //1338668845

    myHeaders.remove("hello");

    System.out.println(System.identityHashCode(head));     //1338668845
    System.out.println(head.size());                 //1
    System.out.println(head);                       //{Accept-Encoding=[gzip]}

    System.out.println(head1);                        //{Accept-Encoding=[gzip]}
    System.out.println(System.identityHashCode(head1));    //1338668845

结论:

案例:3 假设如果我们使用构造函数将 HttpHeaders 对象的空实例传递给 writableHttpHeaders 则没有问题,一切正常
    HttpHeaders head = HttpHeaders.EMPTY;

    System.out.println(System.identityHashCode(head));       //1338668845

    System.out.println(head.size());                     //0

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(new HttpHeaders());

    System.out.println(System.identityHashCode(myHeaders));       //1323165413

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");

    myHeaders.add("hello", "value");

    head = HttpHeaders.EMPTY;
    System.out.println(System.identityHashCode(head));           //1338668845
    System.out.println(head.size());                    //0
    System.out.println(head);                           //{}

    HttpHeaders head1 = HttpHeaders.EMPTY;
    System.out.println(head1);                           //{}
    System.out.println(System.identityHashCode(head1));   //1338668845
Case : 4 尽管可以修改间接不可变的 HttPHeaders.EMPTY,但是如果您尝试直接修改它仍然会抛出错误
    HttpHeaders head = HttpHeaders.EMPTY;

    System.out.println(System.identityHashCode(head));

    System.out.println(head.size());

    HttpHeaders myHeaders = HttpHeaders.writableHttpHeaders(HttpHeaders.EMPTY);

    System.out.println(System.identityHashCode(myHeaders));

    myHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");

    head = HttpHeaders.EMPTY;
    System.out.println(System.identityHashCode(head));
    System.out.println(head.size());
    System.out.println(head);

    head.add("hello", "value");
输出:
1338668845
0
159413332
1338668845
1
{Accept-Encoding=[gzip]}
Exception in thread "main" java.lang.UnsupportedOperationException
at org.springframework.http.ReadOnlyHttpHeaders.add(ReadOnlyHttpHeaders.java:67)
at com.demo.NestedJsonParse.main(NestedJsonParse.java:40)
最终结论: 是的,这是错误,您可以为 spring 项目 spring-bug 提出错误,不可变对象(immutable对象)无法更改状态

关于spring - Spring HttpHeaders 中可能存在的错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53982635/

10-12 03:06