私はあたりOffice365のAPIウェブフックに登録しようとしている公式のAPIドキュメントを。予想通り、私は、郵便配達中のすべての作品を、それを試してみました。
Javaのバージョン:1.7(私は知っています...)
私はプレイフレームワークのバージョンで働いています1.2.7.2
HttpClientを: org.apache.http.client.HttpClient
関連文書:
次のようにサブスクリプションプロセスが行きます:
クライアントアプリケーションは、特定のリソースのサブスクリプション要求(POST)を行います。これは、他の特性の中で、通知URLが含まれています。
展望通知サービスは、リスナー・サービスで通知URLを検証しようとします。これは、検証要求にトークンの検証を含んでいます。
リスナー・サービスが正常にURLを検証する場合は、次のように、それは5秒以内に成功応答を返します。
設定したテキスト\プレーンへのレスポンスヘッダのコンテンツタイプ。レスポンスボディで同じ検証トークンが含まれています。HTTP 200応答コードを返します。リスナーは、その後、トークンの検証を破棄することができます。URLの検証結果によっては、見通しの通知サービスは、クライアントアプリケーションに応答を送信します。
URLの検証が成功した場合、サービスは、ユニークなサブスクリプションIDとサブスクリプションを作成し、クライアントに応答を送信します。URLの検証が失敗した場合、サービスは、エラーコードやその他の詳細とエラー応答を送信します。正常な応答を受信すると、クライアントアプリケーションは、このサブスクリプションと相関将来の通知にサブスクリプションIDを格納します。
郵便配達の要求:
両方の要求は、wiresharkのを傍受しました:
ポストマン:
Ý`!Ë2@ʸ1cÊþßV:
ðîPOST /api/v2.0/me/subscriptions HTTP/1.1
Content-Type: application/json
cache-control: no-cache
Postman-Token: a24df796-c49e-4245-a1cf-0949cd6538b6
Authorization: Bearer ###
User-Agent: PostmanRuntime/7.4.0
Accept: */*
Host: localhost:3000
accept-encoding: gzip, deflate
content-length: 430
Connection: keep-alive
{
"@odata.type":"#Microsoft.OutlookServices.PushSubscription",
"ChangeType": "Created, Deleted, Updated",
"ClientState": "some-token",
"NotificationURL": "https://###/office365/receive.php?subId=5",
"Resource": "https://outlook.office.com/api/v2.0/me/Calendars('###')/events"
}
((wiresharkのでキャプチャ)###
私は認証とIDが一致することを確認しました、部品が情報を削除されます)
で###/office365/receive.php
嘘ばかりエコーがバックPHPスクリプト$_GET['validationtoken']
。これはポストマンで完璧に動作します。
Javaでは、私は、同じヘッダと同じボディで要求を作成します
E/@@5â$¸³zêð-gÄV$
Là¼Là¼POST /api/v2.0/me/subscriptions HTTP/1.1
Accept: */*
Content-Type: application/json
Authorization: Bearer ###
Content-Length: 476
Host: localhost:3000
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.2 (Java/1.7.0_80)
Accept-Encoding: gzip,deflate
{
"@odata.type":"#Microsoft.OutlookServices.PushSubscription",
"ChangeType": "Created, Deleted, Updated",
"ClientState": "1fdb3e372212622e0b7e68abe09e1201a81a8bcc040cce9a6f013f71a09bfbe1",
"NotificationURL": "https://###/office365/receive.php",
"Resource": "https://outlook.office.com/api/v2.0/me/Calendars('###')/events"
}
私は、要求のすべての(重要な)部分がまったく同じであることを確認しました。
Javaで私のコードは完全にここに共有する複雑に少ない、しかし重要なビットは、次のとおりです。
// build url
private final RequestBuilder getRequest (String url) {
RequestBuilder req = RequestBuilder.create(getMethod()); // e.g. POST
req.setUri(overwriteBaseUrl(url) + getPath());
// headers is a hashmap<String, String>
for (String key: headers.keySet()) {
req.setHeader(key, headers.get(key));
}
// set body (handle empty cases)
String body = getBody();
if (body == null) {
body = "";
}
req.setEntity(new StringEntity(body, "UTF-8"));
return req;
}
public void send (HttpClient client, Office365Credentials cred, String url) throws IOException, InvalidCrmCredentialsException, MalformedResponseException {
// creates request (with headers, body, etc)
RequestBuilder req = getRequest(url);
// adds auth
addAuthHeaderToRequest(cred, req);
// execute the request
Response response;
try {
response = new Response(client.execute(req.build()));
} catch (ConnectionPoolTimeoutException e) {
// The 10 second limit has passed
throw new MalformedResponseException("Response missing (response timed out)!", e);
}
// check for 401, not authorized
if (response.getStatus() == 401) {
throw new InvalidCrmCredentialsException("401 - Not authorized! " + req.getUri().toString());
}
// process response
processResponse(response);
}
HttpClientをこのように構成されています。
int CONNECTION_TIMEOUT_MS = 10 * 1000; // 10 second timeout
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(CONNECTION_TIMEOUT_MS)
.setConnectTimeout(CONNECTION_TIMEOUT_MS)
.setSocketTimeout(CONNECTION_TIMEOUT_MS)
.build();
client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
ハイ私は制限を設定する方法に関係なく、私が応答、オフィスのAPIを取得することはありません。さえエラー応答。
TL; DRは:私の要求は、Javaの時代に郵便配達中に微細な、まったく同じ要求をうまくいく(タイムアウトなしの長さを重要で)
問題は、あるorg.apache.http.client.HttpClient
(プレイフレームワーク1.2.7のための少なくとも)スレッドセーフではありません。プレイフレームワークがスレッドを再利用しているので、私の最高の推測では、(ウェブフックレジスタ要求は通常の要求よりも少し時間がかかりますので)それが答えを受けたことがないということ、です。
私はに切り替えWS
プレイフレームワーク自体によって提供されるHTTPクライアント、。このことは、それだけですべてのHTTP動詞を限定的にサポートしていること、欠点が付属しています。
新しいメソッドは次のようになります。
private final WS.WSRequest getRequest (String url) {
WS.WSRequest req = WS.url(overwriteBaseUrl(url) + getPath());
for (String key: headers.keySet()) {
req.setHeader(key, headers.get(key));
}
String body = getBody();
if (body == null) {
body = "";
}
req.body(body);
return req;
}
public void send (WSMockableSender client, Office365Credentials cred, String url) throws IOException, InvalidCrmCredentialsException, MalformedResponseException {
WS.WSRequest req = getRequest(url);
addAuthHeaderToRequest(cred, req);
// execute the request
WSResponse response;
response = new WSResponse(client.post(req));
System.out.println("Response received!");
// check for 401, not authorized
if (response.getStatus() == 401) {
throw new InvalidCrmCredentialsException("401 - Not authorized! " + req.url);
}
processResponse(response);
}