简体   繁体   中英

How to add multiple “Set-Cookie” header in servlet response?

As per RFC http://tools.ietf.org/html/rfc6265#page-7 It is allowed to have two headers with same key of "Set-Cookie". The example provided in RFC is -

​​Set-Cookie: SID=31d4d96e407aad42; Path=/; Secure; HttpOnly
Set-Cookie: ​​lang=en-US; Path=/; Domain=example.com

How​ do ​I achieve same with Jetty(or any other servlet container)? When I call httpServletResponse.addHeader this way-

​httpServletResponse.addHeader("Set-Cookie", "SID=31d4d96e407aad42; Path=/; Secure; HttpOnly");
httpServletResponse.addHeader("Set-Cookie", "lang=en-US; Path=/; Domain=example.com");​

I see that the second addHeader() doesn't add a new header. According to javadoc for this method-

Adds a response header with the given name and value. This method allows response headers to have multiple values.

So it seems that multiple values of allowed but I am not sure how to go about having multiple "Set-Cookie" in servlet response.

Setting Cookies directly like that is a bit awkward, considering that the Servlet API has methods specifically for working with Cookies.

Anyway, tested on Jetty 9.3.0.v20150612 and it works as expected.

Example: SetCookieTest.java

package jetty;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class SetCookieTest
{
    @SuppressWarnings("serial")
    public static class SetCookieAddHeaderServlet extends HttpServlet
    {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
        {
            resp.setContentType("text/plain");
            resp.addHeader("Set-Cookie","SID=31d4d96e407aad42; Path=/; Secure; HttpOnly");
            resp.addHeader("Set-Cookie","lang=en-US; Path=/; Domain=example.com");
            PrintWriter out = resp.getWriter();
            out.println("Hello From: " + this.getClass().getName());
        }
    }

    @SuppressWarnings("serial")
    public static class SetCookieAddCookieServlet extends HttpServlet
    {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
        {
            resp.setContentType("text/plain");

            // Set-Cookie: SID=31d4d96e407aad42; Path=/; Secure; HttpOnly
            Cookie sidCookie = new Cookie("SID","31d4d96e407aad42");
            sidCookie.setPath("/");
            sidCookie.setSecure(true);
            sidCookie.setHttpOnly(true);
            resp.addCookie(sidCookie);

            // Set-Cookie: lang=en-US; Path=/; Domain=example.com
            Cookie langCookie = new Cookie("lang","en-US");
            langCookie.setPath("/");
            langCookie.setDomain("example.com");
            resp.addCookie(langCookie);

            PrintWriter out = resp.getWriter();
            out.println("Hello From: " + this.getClass().getName());
        }
    }

    private static Server server;

    @BeforeClass
    public static void startServer() throws Exception
    {
        server = new Server(9090);
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.addServlet(SetCookieAddHeaderServlet.class,"/test-add-header");
        context.addServlet(SetCookieAddCookieServlet.class,"/test-add-cookie");
        server.setHandler(context);
        server.start();
    }

    @AfterClass
    public static void stopServer() throws Exception
    {
        server.stop();
    }

    /**
     * Issue simple GET request, returning entire response (including payload)
     * 
     * @param uri
     *            the URI to request
     * @return the response
     */
    private String issueSimpleHttpGetRequest(String path) throws IOException
    {
        StringBuilder req = new StringBuilder();
        req.append("GET ").append(path).append(" HTTP/1.1\r\n");
        req.append("Host: localhost\r\n");
        req.append("Connection: close\r\n");
        req.append("\r\n");

        // Connect
        try (Socket socket = new Socket("localhost",9090))
        {
            try (OutputStream out = socket.getOutputStream())
            {

                // Issue Request
                byte rawReq[] = req.toString().getBytes(StandardCharsets.UTF_8);
                out.write(rawReq);
                out.flush();

                // Read Response
                StringBuilder resp = new StringBuilder();
                try (InputStream stream = socket.getInputStream();
                        InputStreamReader reader = new InputStreamReader(stream);
                        BufferedReader buf = new BufferedReader(reader))
                {
                    String line;
                    while ((line = buf.readLine()) != null)
                    {
                        resp.append(line).append(System.lineSeparator());
                    }
                }

                // Return Response
                return resp.toString();
            }
        }
    }

    @Test
    public void testAddHeader() throws Exception
    {
        String response = issueSimpleHttpGetRequest("/test-add-header");
        System.out.println(response);
        assertThat("response", response, containsString("Set-Cookie: SID=31d"));
        assertThat("response", response, containsString("Set-Cookie: lang=en-US"));
    }

    @Test
    public void testAddCookie() throws Exception
    {
        String response = issueSimpleHttpGetRequest("/test-add-cookie");
        System.out.println(response);
        assertThat("response", response, containsString("Set-Cookie: SID=31d"));
        assertThat("response", response, containsString("Set-Cookie: lang=en-US"));
    }
}

Console Output

2015-06-25 14:18:19.186:INFO::main: Logging initialized @167ms
2015-06-25 14:18:19.241:INFO:oejs.Server:main: jetty-9.3.0.v20150612
2015-06-25 14:18:19.276:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@56cbfb61{/,null,AVAILABLE}
2015-06-25 14:18:19.288:INFO:oejs.ServerConnector:main: Started ServerConnector@1ef05443{HTTP/1.1,[http/1.1]}{0.0.0.0:9090}
2015-06-25 14:18:19.289:INFO:oejs.Server:main: Started @270ms
HTTP/1.1 200 OK
Date: Thu, 25 Jun 2015 21:18:19 GMT
Content-Type: text/plain;charset=iso-8859-1
Set-Cookie: SID=31d4d96e407aad42;Path=/;Secure;HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: lang=en-US;Path=/;Domain=example.com
Connection: close
Server: Jetty(9.3.0.v20150612)

Hello From: jetty.SetCookieTest$SetCookieAddCookieServlet

HTTP/1.1 200 OK
Date: Thu, 25 Jun 2015 21:18:19 GMT
Content-Type: text/plain;charset=iso-8859-1
Set-Cookie: SID=31d4d96e407aad42; Path=/; Secure; HttpOnly
Set-Cookie: lang=en-US; Path=/; Domain=example.com
Connection: close
Server: Jetty(9.3.0.v20150612)

Hello From: jetty.SetCookieTest$SetCookieAddHeaderServlet

2015-06-25 14:18:19.405:INFO:oejs.ServerConnector:main: Stopped ServerConnector@1ef05443{HTTP/1.1,[http/1.1]}{0.0.0.0:9090}
2015-06-25 14:18:19.407:INFO:oejsh.ContextHandler:main: Stopped o.e.j.s.ServletContextHandler@56cbfb61{/,null,UNAVAILABLE}

It's probably not the answer you're looking for but I just tried this myself and it worked right away:

Set-Cookie:SID=31d4d96e407aad42; Path=/; Secure; HttpOnly
Set-Cookie:lang=en-US; Path=/; Domain=example.com
Set-Cookie:JSESSIONID=76A68D96ED044DDFF0CC266810F52DDA; Path=/; HttpOnly

That's how the response looked like. Maybe it's the problem of your particular web container, or your implementation.

Try to debug the application (using remote debugging facility) to figure out where the header gets lost.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM