一、场景复现

  营运车应用在登录过程中需要调用用户中心认证的接口来完成统一登录,因为云服务器升级对请求限制https only,在登录过程中出现系统异常(server error服务器异常,status 500)

二、问题排查

  通过kibana追踪日志发现是请求过程中,通过httpclient调用的接口地址是http开头响应码301后没有被重定向到https,由nginx接收转发到应用部署的服务器上,导致调用用户中心认证接口响应异常

<html>
  <head><title>301 Moved Permanently</title></head>
  <body bgcolor="white">
    <center><h1>301 Moved Permanently</h1></center>
    <hr><center>BLB/22.06.1.1</center>
  </body>
</html>

三、原因分析

  Q1——httpclient不支持响应码301/302/307时对post的重定向

  线上服务器因安全问题统一将网站从http升级到https,由云服务器通过负载均衡(blb)访问nginx,项目在sever to sever端是通过Apache HttpClient发送请求,因为项目A在调用项目B接口时的配置类中对项目B的应用地址配置没改成https,请求会先打到http然后返回301,理想情况下当301时httpclient要通过获取location中的新地址重新请求对应的https接口地址,再正确响应。但是使用httpClient进行POST请求调用时,httpClient的默认配置中对可重定向方法只包括GET/HEAD,因此httpclient对301处理时如果请求方法不是GET/HEAD时不会重定向。

org.apache.http.impl.client.DefaultRedirectStrategy

 

/**
     * @since 4.2
     */
    protected boolean isRedirectable(final String method) {
        for (final String m: REDIRECT_METHODS) {
            if (m.equalsIgnoreCase(method)) {
                return true;
            }
        }
        return false;
    }

  
@Override
public boolean isRedirected(
final HttpRequest request,
final HttpResponse response,
final HttpContext context) throws ProtocolException {
Args.notNull(request, "HTTP request");
Args.notNull(response, "HTTP response");

final int statusCode = response.getStatusLine().getStatusCode();
final String method = request.getRequestLine().getMethod();
final Header locationHeader = response.getFirstHeader("location");
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY: //302
return isRedirectable(method) && locationHeader != null;
case HttpStatus.SC_MOVED_PERMANENTLY: //301
case HttpStatus.SC_TEMPORARY_REDIRECT: //307
return isRedirectable(method);
case HttpStatus.SC_SEE_OTHER: //303
return true;
default:
return false;
} //end of switch
}

  Q2——使用DefaultRedirectStrategy(未重写getRedirect方法)支持301 post重定向时,会变成get请求

org.apache.http.impl.client.DefaultRedirectStrategy
  @Override
    public HttpUriRequest getRedirect(
            final HttpRequest request,
            final HttpResponse response,
            final HttpContext context) throws ProtocolException {
        final URI uri = getLocationURI(request, response, context);
        final String method = request.getRequestLine().getMethod();
        if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
            return new HttpHead(uri);
        } else if (method.equalsIgnoreCase(HttpGet.METHOD_NAME)) {
            return new HttpGet(uri);
        } else {
            final int status = response.getStatusLine().getStatusCode();
            if (status == HttpStatus.SC_TEMPORARY_REDIRECT) {
                return RequestBuilder.copy(request).setUri(uri).build();
            } else {
                return new HttpGet(uri);
            }
        }
    }

  

A:继承 DefaultRedirectStrategy类,重写isRedirectable和getRedirect方法

  


 1     @Override
 2     protected boolean isRedirectable(final String method) {
 3         for (final String m : REDIRECT_METHODS) {
 4             if (m.equalsIgnoreCase(method)) {
 5                 return true;
 6             }
 7         }
 8         return false;
 9     }
10 
11     @Override
12     public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context)
13             throws ProtocolException {
14         final URI uri = getLocationURI(request, response, context);
15         final String method = request.getRequestLine().getMethod();
16         if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
17             return new HttpHead(uri);
18         } else if (method.equalsIgnoreCase(HttpGet.METHOD_NAME)) {
19             return new HttpGet(uri);
20         } else {
21             final int status = response.getStatusLine().getStatusCode();
22             if (status == HttpStatus.SC_TEMPORARY_REDIRECT || status == HttpStatus.SC_MOVED_PERMANENTLY) {
23                 return RequestBuilder.copy(request).setUri(uri).build();
24             } else {
25                 return new HttpGet(uri);
26             }
27         }
28     }

View Code