title: SharePoint REST calls with Apache HttpClient and Load Balancing fails after first GET
body: <p>I stumbled on an issue with SharePoint REST calls to a load balancer. When I send the REST calls directly to the webserver, everything seems to work just fine. However, when the REST calls are sent to the load balancer, only the first call gets a HTTP 200 OK status, the rest returns HTTP 401 Unauthorized. After some research I found <a href="https://blog.crsw.com/2008/10/14/unauthorized-401-1-exception-calling-web-services-in-sharepoint/" rel="nofollow noreferrer">this article</a> which says:</p>
  
  <p><em>This isn’t a bug.  There was a security fix built into the Windows networking stack that prevents a machine name that resolves to the loopback address from accepting a connection unless that machine name matches the NETBIOS name.</em></p>
  
  <p>The only workaround stated in that article, is to change the configuration of the servers, which is not a thing our department is willing to do.</p>
  
  <p>The goal would be that we can do SharePoint REST calls from a Java application.</p>
  
  <p>As an example, I made a small test program to that does a GET request to my SharePoint REST API when I press a button.</p>
  
  <p>When I adjust my Windows hosts file to map the load balance url to an ip address of one of our webservers (under the load balancer), everything seems to work just fine:</p>
  
  <pre><code>//first button click
  Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1') HTTP/1.1
  [principal: domain.com\&lt;username&gt;] [workstation: &lt;LBSERVER&gt;]
  ----------------------------------------
  HTTP/1.1 200 OK
  
  //second button click
  Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1') HTTP/1.1
  [principal: domain.com\&lt;username&gt;] [workstation: &lt;LBSERVER&gt;]
  ----------------------------------------
  HTTP/1.1 200 OK
  </code></pre>
  
  <p>However, as soon as we comment out the mapping (and the requests go to the load balancer), the issues start to happen.</p>
  
  <pre><code>//first button click
  Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1') HTTP/1.1
  [principal: domain.com\&lt;username&gt;] [workstation: &lt;LBSERVER&gt;]
  ----------------------------------------
  HTTP/1.1 200 OK
  
  //second button click
  Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('2') HTTP/1.1
  [principal: domain.com\&lt;username&gt;] [workstation: &lt;LBSERVER&gt;]
  ----------------------------------------
  HTTP/1.1 401 Unauthorized
  </code></pre>
  
  <p>As you can see, the first GET request runs just fine. After that, I get the HTTP 401 Unauthorized error.</p>
  
  <p>Why is the HttpClient losing it's authentication/session (as the first request ran fine) even thou the authentication data is inside the HttpContext? Is there anything I am missing in my client code to fix this?</p>
  
  <hr>
  
  <p><strong>Update:</strong></p>
  
  <p>When calling openClient() and closeClient() inside the get() method, both GET requests work fine. But it shouldn't be necessary to recreate the httpClient I assume?</p>
  
  <hr>
  
  <p><strong>Below is the code in full:</strong></p>
  
  <pre><code>CloseableHttpClient httpClient;
  CredentialsProvider credsProvider;
  HttpClientContext context;
  HttpHost targetHost;
  
  Account account;
  
  private void handleButtonAction(ActionEvent event) throws IOException {
      get("https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1')");
  }
  
  private void get(String uri) throws IOException {
      HttpGet httpget = new HttpGet(uri);
  
      System.out.println("\nExecuting request " + httpget.getRequestLine());
  
      CloseableHttpResponse response = httpClient.execute(targetHost, httpget, context);
      System.out.println("----------------------------------------");
      System.out.println(response.getStatusLine());
  
      response.close();
  }
  
  private void openClient() throws IOException {
      System.out.println("Open client");
  
      httpClient = HttpClients.createDefault();
      targetHost = new HttpHost("lbserver.domain.com", 443, "https");
      context = HttpClientContext.create();
  
      credsProvider = new BasicCredentialsProvider();
      credsProvider.setCredentials(
              new AuthScope(targetHost, AuthScope.ANY_REALM, "ntlm"), 
              new NTCredentials(account.getUsername(), account.getPassword(), "lbserver", "domain.com"));
  
      context.setCredentialsProvider(credsProvider);
  
      CookieStore cookieStore = new BasicCookieStore();
      context.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
  }
  
  private void closeClient() throws IOException {
      System.out.println("Close client");
      if (httpClient != null) {
          httpClient.close();
      }
  }
  
  public void initialize(URL url, ResourceBundle rb) {
      account = new Account();
  
      try {
          openClient();
      } catch (IOException ex) {
          Logger.getLogger(FXMLController.class.getName()).log(Level.SEVERE, null, ex);
      }
  
      Runtime.getRuntime().addShutdownHook(new Thread(new Task() {
          @Override
          protected Object call() throws Exception {
              closeClient();
              return null;
          }
      }));
  }
  </code></pre>