Статьи

Обработка cookie для каждого клиента с помощью Jersey

Многие службы REST будут использовать куки как часть схемы аутентификации / авторизации. Это проблема, потому что по умолчанию старый клиент Джерси будет использовать singleton CookieHandler.getDefault, который в большинстве случаев будет нулевым, а если нет, то вряд ли будет работать в многопоточной серверной среде. (Это потому, что в фоновом режиме клиент Джерси по умолчанию будет использовать URL.openConnection).

Теперь вы можете обойти это, используя адаптер Apache HTTP Client для Джерси; но это не всегда доступно. Поэтому, если вы хотите использовать клиент Jersey с файлами cookie в серверной среде, вам нужно немного подумать, чтобы убедиться, что вы используете свой собственный файл cookie.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
final CookieHandler ch = new CookieManager();
     
    Client client = new Client(new URLConnectionClientHandler(
       new HttpURLConnectionFactory() {
 
        @Override
        public HttpURLConnection getHttpURLConnection(URL uRL) throws IOException {
            HttpURLConnection connect = (HttpURLConnection) uRL.openConnection();
 
            try {
                Field cookieField = connect.getClass().getDeclaredField("cookieHandler");
                cookieField.setAccessible(true);
                MethodHandle mh = MethodHandles.lookup().unreflectSetter(cookieField);
                mh.bindTo(connect).invoke(ch);
            } catch (Throwable e) {
                e.printStackTrace();
            }
 
            return connect;
        }
    }));

Это будет работать только в том случае, если ваша среда использует внутреннюю реализацию sun.net.www.protocol.http.HttpURLConnection которая поставляется с JDK. Похоже, это относится к современным версиям WLS.

Для JAX-RS 2.0 вы можете сделать аналогичное изменение, используя класс ClientConfig для Jersey 2.x и HttpUrlConnectorProvider .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
final CookieHandler ch = new CookieManager();
 
 
    Client client =
        ClientBuilder.newClient(new ClientConfig().connectorProvider(new HttpUrlConnectorProvider().connectionFactory(new HttpUrlConnectorProvider.ConnectionFactory() {
            @Override
            public HttpURLConnection getConnection(URL uRL) throws IOException {
                HttpURLConnection connect = (HttpURLConnection) uRL.openConnection();
 
                try {
                    Field cookieField = connect.getClass().getDeclaredField("cookieHandler");
                    cookieField.setAccessible(true);
                    MethodHandle mh = MethodHandles.lookup().unreflectSetter(cookieField);
                    mh.bindTo(connect).invoke(ch);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
 
                return connect;
            }
        })));

Обновление от 11 февраля 2015: в некоторых случаях, в частности, с использованием https, я видел HttpURLConnection, заключенный в другой класс, чтобы обойти это, просто используйте отражение для доступа к значению поля делегата. Я обновил примеры кода, чтобы отразить эту проблему.