Ошибка загрузки нескольких файлов в Box с ошибкой клиента HTTP "соединение все еще установлено"
Я использую Box Java SDK v3.0.5 (последняя версия). В моем приложении я реализую синхронизацию с удаленным пользователем Box, и когда пользователь создает несколько файлов локально, я должен создать их на стороне Box.
Мой клиент создан по следующему коду:
this.client = new BoxClient(key, clientSecret, hub, parser, config);
С загрузкой одного файла все работает хорошо. Но когда несколько файлов представлены один за другим в одном потоке и используют этот код:
BoxFileUploadRequestObject obj = BoxFileUploadRequestObject.uploadFileRequestObject(parentId, name,data);
obj.setLocalFileCreatedAt(created.getTime());
obj.put("created_at", formatDate(created));
return client.getFilesManager().uploadFile(obj);
Я сталкиваюсь со следующим исключением в моем приложении:
java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
at org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:216) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(SingleClientConnManager.java:190) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:401) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732) ~[httpclient-4.1.2.jar:4.1.2]
at com.box.boxjavalibv2.BoxRESTClient.getResponse(BoxRESTClient.java:148) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:98) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:72) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.AbstractBoxResourceManager.getResponseAndParse(AbstractBoxResourceManager.java:118) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.filetransfer.BoxFileUpload.execute(BoxFileUpload.java:58) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.BoxFilesManagerImpl.uploadFile(BoxFilesManagerImpl.java:134) ~[boxjavalibv2-3.0.5.jar:na]
at org.exoplatform.clouddrive.box.BoxAPI.createFile(BoxAPI.java:745) ~[exo-clouddrive-services-core-1.1.0-SNAPSHOT.jar:1.1.0-SNAPSHOT]
.........
Наконец, только первый файл успешно загружен.
После поиска этой ошибки я обнаружил, что может помочь использование многопоточного соединения. Но так как этот код находится в Box SDK, единственное, что я смог попробовать, это использование BoxConnectionManager (который обеспечивает поточно- ориентированный режим) при создании клиента:
BoxConnectionManagerBuilder connManager = new BoxConnectionManagerBuilder();
this.client = new BoxClient(key, clientSecret, hub, parser, config, connManager.build());
Действительно, с диспетчером соединений, отправленным клиенту, возникает другая проблема, когда я пытаюсь получить доступ к службе Box API:
Caused by: com.box.restclientv2.exceptions.BoxRestException: null
at com.box.boxjavalibv2.BoxRESTClient.handleException(BoxRESTClient.java:183) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:118) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:72) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.AbstractBoxResourceManager.getResponseAndParse(AbstractBoxResourceManager.java:118) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.AbstractBoxResourceManager.getResponseAndParseAndTryCast(AbstractBoxResourceManager.java:108) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.resourcemanagers.BoxEventsManagerImpl.getEventOptions(BoxEventsManagerImpl.java:60) ~[boxjavalibv2-3.0.5.jar:na]
at org.exoplatform.clouddrive.box.BoxAPI.updateChangesLink(BoxAPI.java:671) ~[exo-clouddrive-services-core-1.1.0-SNAPSHOT.jar:1.1.0-SNAPSHOT]
... 76 common frames omitted
Caused by: javax.net.ssl.SSLException: hostname in certificate didn't match: <api.box.com/74.112.185.97> != <*.box.com> OR <*.box.com> OR <box.com>
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:228) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:495) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.conn.scheme.SchemeSocketFactoryAdaptor.connectSocket(SchemeSocketFactoryAdaptor.java:62) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754) ~[httpclient-4.1.2.jar:4.1.2]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732) ~[httpclient-4.1.2.jar:4.1.2]
at com.box.boxjavalibv2.BoxRESTClient.getResponse(BoxRESTClient.java:148) ~[boxjavalibv2-3.0.5.jar:na]
at com.box.boxjavalibv2.BoxRESTClient.execute(BoxRESTClient.java:98) ~[boxjavalibv2-3.0.5.jar:na]
... 81 common frames omitted
К сведению, в моей среде разработчиков я использую Tomcat на 8443 порту. Но с REST-клиентом по умолчанию (без менеджера соединений, размещенного в конструкторе клиента) все работало хорошо.
Какое решение я могу использовать для загрузки нескольких файлов в Box?
2 ответа
Я отвечаю на свой вопрос сам.
Первоначальная проблема "соединение еще выделено" была действительно актуальной, как предполагалось в вопросе выше. Коренной причиной была необходимость
Потокобезопасное соединение (для HTTP-клиента в Box SDK)... Но так как этот код находится в Box SDK, единственное, что мне удалось попробовать, - это использование BoxConnectionManager (который обеспечивает поточно-ориентированное).
Но когда я использовал BoxConnectionManager
Я столкнулся со второй упомянутой ошибкой: имя хоста в сертификате не совпадало. Эта ошибка связана с различными версиями HTTP-клиента Apache на пути к классам. Мой сервер (eXo Platform 4.0) предоставляет HTTP-клиент Apache 4.1.2, но для Box SDK требуется 4.2.5. После установки моего приложения серверные библиотеки имеют оба этих JAR-файла, и 4.1.2 отображается как загруженный для Box. Если удалить JAR из 4.1.2, то все работает как положено, и те, кто может сделать это, не столкнутся с ошибкой SSL-сертификата, как я. Но я не могу сделать это, так как другие части eXo сертифицированы с помощью HTTP-клиента 4.1.2, и я не хочу рисковать ими.
Мое решение - использование пользовательских BoxRESTClient
в BoxClient
, Благодаря команде Box можно создать экземпляр своего клиента с деталями низкого уровня, такими как клиент REST. BoxConnectionManager
скрывает это, предоставляя собственный BoxRESTClient
, но также возможно создать этот клиент REST из внешнего кода, без использования менеджера. Мой пользовательский REST-клиент адаптирован к HTTP-клиенту 4.1.2 и имеет "разрешающий всем" верификатор имени хоста.
Пока что мое решение приемлемо и работает хорошо. Ниже фрагментов кода, которые я использовал:
Как создать Box-клиент:
BoxResourceHub hub = new BoxResourceHub();
BoxJSONParser parser = new BoxJSONParser(hub);
this.client = new BoxClient(key,
clientSecret,
hub,
parser,
new RESTClient(),
new BoxConfigBuilder().build());
И обычай RESTClient
:
class RESTClient extends BoxRESTClient {
final HttpClient httpClient;
@SuppressWarnings("deprecation")
RESTClient() {
super();
SchemeRegistry schemeReg = new SchemeRegistry();
schemeReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
SSLSocketFactory socketFactory;
try {
socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS,
null,
null,
null,
null,
null,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
} catch (Exception ex) {
throw new IllegalStateException("Failure initializing default SSL context for Box REST client", ex);
}
schemeReg.register(new Scheme("https", socketFactory, 443));
ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(new BasicHttpParams(), schemeReg);
this.httpClient = new DefaultHttpClient(connectionManager);
}
@Override
public HttpClient getRawHttpClient() {
return httpClient;
}
}
Таким образом Box SDK работает хорошо и может загружать несколько файлов в пользовательский ящик.
Из трассировки стека это выглядит так, как будто ssl-сертификат не установлен. Можете ли вы попробовать запустить оба кода (с и без ConnectionManager) на одном компьютере? Один потерпит неудачу, а другой преуспеет?