草庐IT

java - 在 Java Apache 中相同的请求超时,在 postman 中工作正常

coder 2024-03-13 原文

我正在尝试根据 official api docs 注册一个 Office365 Api webhook .我在 postman 中试过了,一切都按预期工作。

Java 版本:1.7(我知道...)

我正在使用 Play 框架版本 1.2.7.2

HttpClient: org.apache.http.client.HttpClient

相关文档:

The subscription process goes as follows:

A client app makes a subscription request (POST) for a specific resource. It includes a notification URL, among other properties.

The Outlook notifications service tries to validate the notification URL with the listener service. It includes a validation token in the validation request.

If the listener service successfully validates the URL, it returns a success response within 5 seconds as follows:

Sets the content type in the response header to text\plain. Includes the same validation token in the response body. Returns an HTTP 200 response code. The listener can discard the validation token subsequently. Depending on the URL validation result, the Outlook notifications service sends a response to the client app:

If URL validation was successful, the service creates the subscription with a unique subscription ID and sends the response to the client. If URL validation was unsuccessful, the service sends an error response with an error code and other details. Upon receiving a successful response, the client app stores the subscription ID to correlate future notifications with this subscription.

postman 请求:

两个请求都被wireshark拦截了:

postman :

Ý`!Ë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 中捕获)(### 部分已删除信息,我确保 auth 和 ids 匹配)

###/office365/receive.php 处有一个 php 脚本,它只是回显 $_GET['validationtoken']。这在 Postman 中非常有效。

在 Java 中,我创建了一个具有相同 header 和相同正文的请求

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();

无论我设置多高的限制,我都得不到响应,office api。甚至没有错误响应。

TL;DR:我的请求在 postman 中工作正常,在 Java 中完全相同的请求超时(无论超时长度如何)

最佳答案

问题是,org.apache.http.client.HttpClient 不是线程安全的(至少对于 play framework 1.2.7 而言)。由于 play 框架重用线程,我最好的猜测是,它从未收到答案(因为 webhook 注册请求比正常请求花费的时间稍长)。

我切换到 WS,play 框架本身提供的 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);
}

关于java - 在 Java Apache 中相同的请求超时,在 postman 中工作正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53194046/

有关java - 在 Java Apache 中相同的请求超时,在 postman 中工作正常的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  3. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  4. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  5. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  6. ruby-on-rails - 无法让 rspec、spork 和调试器正常运行 - 2

    GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'

  7. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  8. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  9. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  10. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

随机推荐