简体   繁体   English

检测Java中的HTTP中断

[英]Detect HTTP interruption in Java

I'm making a REST call to an external system from Java. 我正在用Java从外部系统调用REST。 If there are any connection interruptions like if the external system goes offline, I need a listener to detect that and perform corresponding actions. 如果有任何连接中断,如外部系统脱机,我需要一个侦听器来检测并执行相应的操作。 Kindly let me know if I can achieve this in Java. 如果我能用Java实现这一点,请告诉我。 Preferably in Java 8. 优选地在Java 8中。

Currently i'm not getting any exception if I get into any such situation. 如果我遇到任何这种情况,目前我没有任何例外。 I having the below code currently 我目前有以下代码

    Client client = ClientBuilder.newClient();
    WebTarget target = client.target(HOSTNAME);
    Invocation.Builder requestBuilder;

    requestBuilder = target.path(URL).request(MediaType.APPLICATION_JSON)
                                                .header(HEADER_AUTHORIZATION, AUTH_TOKEN);      
    Response response = null;
    if (HTTP_POST.equalsIgnoreCase(method)) {
        try{
        response = requestBuilder.post(Entity.entity(message, MediaType.APPLICATION_JSON_TYPE));
        }catch(Exception ex ){
            ex.printStackTrace();
        }
    } else if (HTTP_GET.equalsIgnoreCase(method)) {
        response = requestBuilder.get();
    } 

    String executeMessage = null;
    if(response != null){
        if (response.getStatus() == 200) {
            executeMessage = response.readEntity(String.class);         
            return new JSONObject(executeMessage);
        } else {
            executeMessage = response.readEntity(String.class);
            final JSONObject status = new JSONObject();
            status.put(STATUS_CODE, response.getStatus());
            status.put(STATUS_INFO, response.getStatusInfo());
            status.put("response", executeMessage);
            final JSONObject error = new JSONObject();
            error.put(ERROR, status);
            return error;
        }
    }

If you use Spring Boot you can try a declarative REST client called Feign : 如果您使用Spring Boot,您可以尝试一个名为Feign的声明性REST客户端:

@FeignClient(url = "example.com", fallback = YourTestFeignClient.YourTestFeignClientFallback.class)
public interface YourTestFeignClient {

    @RequestMapping(method = RequestMethod.POST, value = "/example/path/to/resource/{id}")
    YourTestResponse requestExternalResource(@RequestParam("id") Long id, SomeRequestDTO requestDTO);

    @Component
    public static class YourTestFeignClientFallback implements YourTestFeignClient {

        @Override
        public YourTestResponse requestExternalResource(Long id, SomeRequestDTO requestDTO) {
            YourTestResponse testResponse = new YourTestResponse();
            testResponse.setMessage("Service unavailable");
            return testResponse;
        }

    }
}

All you need to do here is to inject YourTestFeignClient in your code and invoke method requestExternalResource on it. 你需要做的就是在代码中注入YourTestFeignClient并在其上调用方法requestExternalResource This will call POST example.com/example/path/to/resource/34 with JSON body taken from SomeRequestDTO . 这将调用POST example.com/example/path/to/resource/34其中JSON主体取自SomeRequestDTO In case a request fails a fallback method inside YourTestFeignClientFallback will get called, which then returns some default data. 如果请求失败,将调用YourTestFeignClientFallback的回退方法,然后返回一些默认数据。

You could create your own Listener and make your Http calls async with the results passed back to the calling class once the HTTP response/error is ready. 您可以创建自己的侦听器,并在HTTP响应/错误就绪后将结果传递回调用类,使您的Http调用异步。 For example (with typos): 例如(使用拼写错误):

Create an interface that your main class will implement and your Http Client will make use of... 创建一个主类将实现的接口,您的Http客户端将使用...

public interface MyHttpListener {
  public httpComplete(MyHttpResults results);
}

Implement in your main class. 在你的主类中实现。

public MyClass implements MyHttpListener {

  public void processHttpRequests(){
      for(int i=0; i<10; i++){
        // instantiate your Http Client class 
        HttpClient client = new HttpClient();

        // register the listener
        client.addHttpListener(this);

        // execute whatever URL you want and you are notified later when complete
        client.executeRequest("http://whatever");
     }
  }

  public httpRequestComplete(MyHttpResults results) {
    // do something with the results   
    results.getResponseCode();
    results.getRawResponse();
    results.whatever();
  }  

} }

Add method to your HttpClient to accept listeners 向HttpClient添加方法以接受侦听器

public class MyHttpClient {
    List<MyHttpListener> httpListenerList = new ArrayList();   

   // register listeners
   public void addHttpListener(MyHttpListener listener){
     httpListenerList.add(listener);
   }   

   // this is the method that processes the request
   public void executeRequest(String url) {

     // do whatever you were doing previously here   

     // optional POJO to wrap the results and/or exceptions
     MyHttpResults results = new MyHttpResults();
     results.withResponseCode(response.getResponseCode());
     results.withResponse(responseAsString);
     results.withException(ex);
     results.withWhatever(whatever);

     // notify listeners
     notify(results);

   }

  public void notify(MyHttpResults results){
      // notify listeners
      for(MyHttpListener listener : httpListenerList){
         listener.httpComplete(results);
      }
  }


 }

If you want to constantly check external REST service whether it is offline you have to setup some sort of periodical ping request. 如果要持续检查外部REST服务是否处于脱机状态,则必须设置某种定期ping请求。 Any response will mean that service is online. 任何回复都意味着服务在线。 Absence of response during some period of time will mean that something is wrong. 在一段时间内没有回应意味着出现了问题。

The problem you are facing rises from that java TCP Socket connect method is blocking and java socket default connect timeout is 0, which is actually infinity as it is said in javadoc . 您面临的问题是java TCP Socket connect方法阻塞而java套接字默认连接超时为0,这实际上是无穷大,就像在javadoc中所说的那样。

So that means that you won't get any response at all by default if the service is offline. 这意味着如果服务处于脱机状态,默认情况下您根本不会得到任何响应。

The only correct and simple option here is to set a timeout. 这里唯一正确和简单的选择是设置超时。 In your case the easiest way would be to use Jersey Client property setup, like this: 在您的情况下,最简单的方法是使用Jersey Client属性设置,如下所示:

Client client = ClientBuilder.newClient();
// One second timeout may not be a really good choice unless your network is really fast
client.property(ClientProperties.CONNECT_TIMEOUT, 1000); 

And only in this case you will get an exception, which will indicate, that REST service you are trying to ping is not accepting connections. 并且只有在这种情况下,您将获得一个异常,这将表明您尝试ping的REST服务不接受连接。

Set timeout with caution according to the real network capabilities, in some cases it should be more than 5 or even 15 seconds (eg WiFi and GPRS connections). 根据实际网络功能谨慎设置超时,在某些情况下应超过5秒甚至15秒(例如WiFi和GPRS连接)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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