A Guide To HTTP Cookies In Java – Java中的HTTP Cookies指南

最后修改: 2016年 11月 9日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we are going to explore low-level operations with Java network programming. We’ll be taking a deeper look at Cookies.

在这篇文章中,我们将探讨Java网络编程的低层次操作。我们将更深入地研究Cookies。

The Java platform ships with built-in networking support, bundled up in the java.net package:

Java平台有内置的网络支持,捆绑在java.net包中。

import java.net.*;

2. HTTP Cookies

2.HTTP Cookies

Whenever a client sends an HTTP request to a server and receives a response for it, the server forgets about this client. The next time the client requests again, it will be seen as a totally new client.

每当一个客户向服务器发送HTTP请求并收到一个响应时,服务器就会忘记这个客户。下次该客户再次请求时,它将被视为一个全新的客户。

However, cookies, as we know, make it possible to establish a session between the client and server such that the server can remember the client across multiple request response pairs.

然而,正如我们所知,cookies使得在客户和服务器之间建立一个会话成为可能,这样服务器就可以在多个请求响应对中记住客户。

From this section henceforth, we will learn how to use cookies to enhance our client-server communications in Java network programming.

从本节开始,我们将学习如何在Java网络编程中使用cookies来增强我们的客户-服务器通信。

The main class in the java.net package for handling cookies is CookieHandler. There are other helper classes and interfaces such as CookieManager, CookiePolicy, CookieStore, and HttpCookie.

java.net包中用于处理cookie的主要类是CookieHandler。还有其他辅助类和接口,如CookieManagerCookiePolicyCookieStoreHttpCookie

3. The CookieHandler Class

3.CookieHandler

Consider this scenario; we are communicating with the server at http://baeldung.com, or any other URL that uses HTTP protocol, the URL object will be using an engine called the HTTP protocol handler.

考虑这种情况;我们在http://baeldung.com与服务器通信,或任何其他使用HTTP协议的URL,URL对象将使用一个称为HTTP协议处理器的引擎。

This HTTP protocol handler checks if there is a default CookieHandler instance in the system. If there is, it invokes it to take charge of state management.

这个HTTP协议处理程序检查系统中是否有一个默认的CookieHandler实例。如果有,它将调用它来负责状态管理。

So the CookieHandler class has a purpose of providing a callback mechanism for the benefit of the HTTP protocol handler.

因此,CookieHandler类的目的是为HTTP协议处理程序的利益提供一个回调机制。

CookieHandler is an abstract class. It has a static getDefault() method that can be called to retrieve the current
CookieHandler installation or we can call setDefault(CookieHandler) to set our own. Note that calling setDefault installs a CookieHandler object on a system-wide basis.

CookieHandler是一个抽象的类。它有一个静态的getDefault()方法,可以被调用来检索当前的
CookieHandler安装。
CookieHandler安装,或者我们可以调用setDefault(CookieHandler)来设置我们自己的。请注意,调用setDefault会在全系统范围内安装一个CookieHandler对象。

It also has put(uri, responseHeaders) for saving any cookies to the cookie store. These cookies are retrieved from the response headers of the HTTP response from the given URI. It’s called every time a response is received.

它也有put(uri, responseHeaders),用于将任何cookie保存到cookie存储器中。这些cookie是从给定URI的HTTP响应的响应头中检索出来的。每次收到响应时都会调用它。

A related API method – get(uri,requestHeaders) retrieves the cookies saved under the given URI and adds them to the requetHeaders. It’s called just before a request is made.

一个相关的API方法–get(uri,requestHeaders)检索保存在给定URI下的cookies,并将它们添加到requetHeaders中。它在请求发出之前被调用。

These methods must all be implemented in a concrete class of CookieHandler. At this point, the CookieManager class is worth our attention. This class offers a complete implementation of CookieHandler class for most common use cases.

这些方法都必须在CookieHandler的一个具体类中实现。在这一点上,CookieManager类值得我们关注。这个类为大多数常见的使用情况提供了CookieHandler类的完整实现。

In the next two sections, we are going to explore the CookieManager class; first in its default mode and later in custom mode.

在接下来的两节中,我们将探讨CookieManager类;首先在其默认模式下,然后在自定义模式下。

4. The Default CookieManager

4.默认的CookieManager

To have a complete cookie management framework, we need to have implementations of CookiePolicy and CookieStore.

为了拥有一个完整的cookie管理框架,我们需要有CookiePolicyCookieStore的实现。

CookiePolicy establishes the rules for accepting and rejecting cookies. We can of course change these rules to suit our needs.

CookiePolicy 建立了接受和拒绝cookies的规则。当然,我们可以改变这些规则以适应我们的需要。

Next – CookieStore does exactly what it’s name suggests, it has methods for saving and retrieving cookies. Naturally we can tweak the storage mechanism here as well if we need to.

下一步 – CookieStore 就像它的名字所暗示的那样,它有保存和检索cookies的方法。当然,如果需要的话,我们也可以在这里对存储机制进行调整。

Let’s first look at the defaults. To create the default CookieHandler and set it as the system-wide default:

让我们先看一下默认值。要创建默认的CookieHandler并将其设置为全系统的默认值。

CookieManager cm = new CookieManager();
CookieHandler.setDefault(cm);

We should note that the default CookieStore will have volatile memory i.e. it only lives for the lifetime of the JVM. To have a more persistent storage for cookies, we must customize it.

我们应该注意到,默认的CookieStore将具有易失性内存,即它只在JVM的生命周期内存在。要想对Cookie进行更持久的存储,我们必须对它进行定制。

When it comes to CookiePolicy, the default implementation is CookiePolicy.ACCEPT_ORIGINAL_SERVER. This means that if the response is received through a proxy server, then the cookie will be rejected.

当涉及到CookiePolicy时,默认实现是CookiePolicy.ACCEPT_ORIGINAL_SERVER。这意味着,如果通过代理服务器收到响应,那么cookie将被拒绝。

5. A Custom CookieManager

5.一个自定义的CookieManager

Let’s now customize the default CookieManager by providing our own instance of CookiePolicy or CookieStore (or both).

现在让我们通过提供我们自己的CookiePolicyCookieStore(或两者)的实例来定制默认的CookieManager

5.1. CookiePolicy

5.1.CookiePolicy

CookiePolicy provides some pre-defined implementations for convenience:

CookiePolicy为方便起见提供了一些预定义的实现。

  • CookiePolicy.ACCEPT_ORIGINAL_SERVER – only cookies from the original server can be saved (the default implementation)
  • CookiePolicy.ACCEPT_ALL – all cookies can be saved regardless of their origin
  • CookiePolicy.ACCEPT_NONE – no cookies can be saved

To simply change the current CookiePolicy without implementing our own, we call the setCookiePolicy on the CookieManager instance:

为了简单地改变当前的CookiePolicy而不实现我们自己的,我们在CookieManager实例上调用setCookiePolicy

CookieManager cm=new CookieManager();
cm.setCookiePolicy(CookiePolicy.ACCEPT_ALL);

But we can do a lot more customization than this. Knowing the behavior of CookiePolicy.ACCEPT_ORIGINAL_SERVER, let’s assume we trust a particular proxy server and would like to accept cookies from it on top of the original server.

但我们可以做比这更多的定制。了解了CookiePolicy.ACCEPT_ORIGINAL_SERVER的行为,让我们假设我们信任一个特定的代理服务器,并希望在原始服务器的基础上接受它的cookies。

We’ll have to implement the CookiePolicy interface and implement the shouldAccept method; it’s here where we’ll change the acceptance rule by adding the chosen proxy server’s domain name.

我们必须实现CookiePolicy接口并实现shouldAccept方法;在这里我们将通过添加所选代理服务器的域名来改变接受规则。

Let’s call the new policy – ProxyAcceptCookiePolicy. It will basically reject any other proxy server from its shouldAccept implementation apart from the given proxy address, then call the shouldAccept method of the CookiePolicy.ACCEPT_ORIGINAL_SERVER to complete the implementation:

让我们称这个新策略为–ProxyAcceptCookiePolicy。它基本上会从它的shouldAccept实现中拒绝除给定代理地址之外的任何其他代理服务器,然后调用CookiePolicy.ACCEPT_ORIGINAL_SERVERshouldAccept方法来完成实现。

public class ProxyAcceptCookiePolicy implements CookiePolicy {
    private String acceptedProxy;

    public boolean shouldAccept(URI uri, HttpCookie cookie) {
        String host = InetAddress.getByName(uri.getHost())
          .getCanonicalHostName();
        if (HttpCookie.domainMatches(acceptedProxy, host)) {
            return true;
        }

        return CookiePolicy.ACCEPT_ORIGINAL_SERVER
          .shouldAccept(uri, cookie);
    }

    // standard constructors
}

When we create an instance of ProxyAcceptCookiePolicy, we pass in a String of the domain address we would like to accept cookies from in addition to the original server.

当我们创建ProxyAcceptCookiePolicy的实例时,我们传入一个我们希望在原始服务器之外接受cookies的域名地址的字符串。

We then set this instance as the cookie policy of the CookieManager instance before setting it as the default CookieHandler:

然后我们把这个实例设置为CookieManager实例的cookie策略,再把它设置为默认的CookieHandler。

CookieManager cm = new CookieManager();
cm.setCookiePolicy(new ProxyAcceptCookiePolicy("baeldung.com"));
CookieHandler.setDefault(cm);

This way the cookie handler will accept all cookies from the original server and also those from http://www.baeldung.com.

这样,cookie处理程序将接受来自原始服务器的所有cookie,也接受来自http://www.baeldung.com的cookie。

5.2. CookieStore

5.2.CookieStore

CookieManager adds the cookies to the CookieStore for every HTTP response and retrieves cookies from the CookieStore for every HTTP request.

CookieManager为每个HTTP响应添加Cookie到CookieStore,为每个HTTP请求从CookieStore检索Cookie。

The default CookieStore implementation does not have persistence, it rather loses all it’s data when the JVM is restarted. More like RAM in a computer.

默认的CookieStore实现没有持久性,而是在JVM重新启动时丢失所有的数据。更像是计算机中的RAM。

So if we would like our CookieStore implementation to behave like the hard disk and retain the cookies across JVM restarts, we must customize it’s storage and retrieval mechanism.

因此,如果我们希望我们的CookieStore实现能够像硬盘一样,在JVM重新启动时保留cookie,我们必须定制它的存储和检索机制。

One thing to note is that we cannot pass a CookieStore instance to CookieManager after creation. Our only option is to pass it during the creation of CookieManager or obtain a reference to the default instance by calling new CookieManager().getCookieStore() and complementing its behavior.

有一点需要注意的是,我们不能在创建后将CookieStore实例传递给CookieManager。我们唯一的选择是在创建CookieManager时传递它,或者通过调用new CookieManager().getCookieStore()获得对默认实例的引用并补充其行为。

Here is the implementation of PersistentCookieStore:

这里是PersistentCookieStore的实现。

public class PersistentCookieStore implements CookieStore, Runnable {
    private CookieStore store;

    public PersistentCookieStore() {
        store = new CookieManager().getCookieStore();
        // deserialize cookies into store
        Runtime.getRuntime().addShutdownHook(new Thread(this));
    }

    @Override
    public void run() {
        // serialize cookies to persistent storage
    }

    @Override
    public void add(URI uri, HttpCookie cookie) {
        store.add(uri, cookie);

    }
    
    // delegate all implementations to store object like above
}

Notice that we retrieved a reference to the default implementation in the constructor.

注意,我们在构造函数中检索了对默认实现的引用。

We implement runnable so that we can add a shutdown hook that runs when the JVM is shutting down. Inside the run method, we persist all our cookies into memory.

我们实现了runnable,这样我们就可以添加一个关机钩,在JVM关闭时运行。在run方法中,我们将所有的cookies持久化到内存中。

We can serialize the data into a file or any suitable storage. Notice also that inside the constructor, we first read all cookies from persistent memory into the CookieStore. These two simple features make the default CookieStore essentially persistent (in a simplistic way).

我们可以将数据序列化到一个文件或任何合适的存储中。还请注意,在构造函数中,我们首先从持久性内存中读取所有的cookie到CookieStore中。这两个简单的特征使得默认的CookieStore本质上是持久的(以一种简单的方式)。

6. Conclusion

6.结论

In this tutorial, we covered HTTP cookies and showed how to access and manipulate them programmatically.

在本教程中,我们介绍了HTTP cookie,并展示了如何以编程方式访问和操纵它们。

The full source code for the article and all code snippets can be found in the GitHub project.

文章的完整源代码和所有代码片段都可以在GitHub项目中找到。