There is a problem with the newly online service. The server response status code 401 appears on the interface calling the third party.

What is the meaning of HTTP Code 401? What is the meaning of HTTP Code 400,401,403? 401 Unauthorized: requests are sent with HTTP authentication information

The 401 is the status code of the server response, and X_API_KEY is added to the request header according to the interface document for interface validation, which is implemented in the code.

And the same interface sends the request locally without problems, here is using Hutool (version 3.3.2) toolkit to send THE HTTP request, calling the third party interface to fetch the data. The project code is deployed on a Linux server (IP: 192.168.0.211), and graphic tools such as Wireshark cannot be used. Therefore, the tcpdump command is used to capture packets.

Tcpdump -i eth0 TCP port 80 and host 192.168.67.206 -w/TMP /httptool-206.pcap -i eth0 Specifies the network adapter TCP specified protocol port 80 Specifies the port host 192.168.67.206 Specifies the IP address. It indicates that packets received and sent by the host 192.168.67.206 are captured. -w Writes captured packets to a fileCopy the code

Transfer the captured data packets to the local host. Use Wireshark to open the following command

The fourth line is the HTTP GET request that is issued. Notice that the request header contains cookie information, and the code does not set the cookie. So how does this cookie come from? When the cookie is displayed in the local code, an 401 Unauthorized exception occurs during local debugging, which may be caused by the cookie. Decided to look at the Hutool toolkit HttpRequest class implementation source code is how to automatically set cookies.

Our business code

  String result = HttpRequest.get(url) // Set the request URL
      .header(X_API_KEY, apiKey) / / set the header
      .timeout(TIME_OUT) // Set the timeout period
      .execute().body();
Copy the code

To set the parameters required for the request, look at the execute() method in HttpRequest

/** * Execute Reuqest request **@return this
 */
public HttpResponse execute(a) {
    return this.execute(false);
}
Copy the code

Continue to follow

/** * Execute Reuqest request **@paramIsAsync Whether asynchronous *@return this
 */
public HttpResponse execute(boolean isAsync) {
    // Initialize the URL
    urlWithParamIfGet();
    // Initialize connection
    initConnecton();

    // Send the request
    send();

    // Implement redirection manually
    HttpResponse httpResponse = sendRedirectIfPosible();

    // Get the response
    if(null == httpResponse){
        httpResponse = new HttpResponse(this.httpConnection, this.charset, isAsync, isIgnoreResponseBody());
    }
    return httpResponse;
}
Copy the code

Go to the initConnecton() method

/** * Initialize the network connection */
private void initConnecton(a){
    // Initialize connection
    this.httpConnection = HttpConnection
        .create(this.url, this.method, this.hostnameVerifier, this.ssf, this.timeout, this.proxy)
        .header(this.headers, true); // Override the default Header

    // Customize the Cookie
    if(null! =this.cookie){
        this.httpConnection.setCookie(this.cookie);
    }

    // Whether to disable caching
    if(this.isDisableCache){
        this.httpConnection.disableCache();
    }

    // Define forwarding
    this.httpConnection.setInstanceFollowRedirects(maxRedirectCount > 0 ? true : false);
}
Copy the code

this.httpConnection.setCookie(this.cookie); As you can see, if we show that a cookie is specified, this is set through the setCookie method in the HttpConnection

/** * Set Cookie **@param cookie Cookie
 * @return this
 */
public HttpConnection setCookie(String cookie) {
    if(cookie ! =null) {
        log.debug("Cookie: {}", cookie);
        header(Header.COOKIE, cookie, true);
    }
    return this;
}
Copy the code

Here we do not specify a cookie in the code, so is this method invoked elsewhere in the code?

So put a breakpoint in the setCookie method and run the code to debug it. From the Frames window in IDEA, you can locate where the setCookie method is called. Sure enough, setCookie is called in the initConn method of HttpConnection. Get a cookie from CookiePool based on the host in the URL.

CookiePool is a static Map, the key is host, and the value is a string of cookies. CookiePool is used to simulate the cookies of the browser. When you visit the site, record the cookies, and next time you visit the site, Submit cookies to the site. This means that all future requests will carry this cookie.

package com.xiaoleilu.hutool.http;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/ * * * Cookie pool. This pool is available for all HTTP requests. <br> * This Cookie pool is used to simulate the cookies of the browser. When the site is accessed, the Cookie is recorded, and the next time the site is accessed, the Cookie is submitted to the site. *@author Looly
 *
 */
public class CookiePool {
	
	// Key: host, value: cookies String
	private static Map<String, String> cookies = new ConcurrentHashMap<String, String>();
	
	/** * Obtain Cookie information for a website *@paramHost site host *@returnCookie string */
	public static String get(String host) {
		return cookies.get(host);
	}
	
	/** * Put a site's cookies into the Cookie pool *@paramHost site host *@paramCookie Cookie character string */
	public static void put(String host, String cookie) {
		cookies.put(host, cookie);
	}
	
	/** * Clear Cookie *@since3.0.7 * /
	public static void clear(a){ cookies.clear(); }}Copy the code

So where does this cookie come from? Continuing to look at where the put method in CookiePool is called, the storeCookie method is found in the HttpConnection class

/** * Store the cookies returned by the server to the local */
private void storeCookie(a) {
    final String setCookie = header(Header.SET_COOKIE);
    if (StrUtil.isBlank(setCookie) == false) {
        log.debug("Set cookie: [{}]", setCookie); CookiePool.put(url.getHost(), setCookie); }}Copy the code

In the HttpRequest the execute () method to send a request, when acquiring the response data is called the httpConnection. GetInputStream (), for server to return information, extracted from response headers Set – that the value of the Cookie, Save to CookiePool.

It turns out that most of our interfaces are based on third-party interfaces, and X_API_KEY is added to the request header for interface authentication. However, there is one interface that is not provided by the third party, so we log in to the website by simulating login to capture data. When the login interface is activated, The third-party server returns set-cookie information in the response, and the Hutool extracts set-cookie information from the response, saves it in the CookiePool, and carries the Cookie in subsequent requests.

Cookies returned by the login interface of a third-party website

Since we don’t want this cookie, we can call the put method in CookiePool to reset the cookie for host to null, so that other requests to the same host don’t carry cookies.

/ / remove the cookie
CookiePool.put(ip, null);
Copy the code

In conclusion, this article through tcpdump packet capture tool, view the complete HTTP request, analyze the Hutool tool to send HTTP request process source code, and finally locate and solve the problem.

More exciting content please follow the public geekymv, like please share with more friends oh”