1.1.0 关于SpringBoot中利用RestTemplate请求第三方接口出现406问题处理

1、406问题存在的问题主要原因:请求方和被请求方中的Accept类型不匹配,比如,被请求方式是:“application/json”,被请求方是:“application/octet-stream”,那么就会出现406,在处理过程中,发现双方都是“application/json”,不知道问题究竟出现在哪里;后面通过同事帮助排查,发现自己犯下了一个低级的错误,以此记录以下:
请求第三方我是通过基础类封装的:

@Component
public final class HttpTemplateUtil {

    private static Logger logger = LoggerFactory.getLogger(HttpTemplateUtil.class);

    private static RestTemplate restTemplate;

    @Resource(name = "restTemplate")
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public static MultiValueMap<String,String> packHeader(MultiValueMap<String, String> headerParams){
        if (headerParams == null) {
            headerParams = new LinkedMultiValueMap();
            headerParams.add("Accept", "application/json");
            headerParams.add("Accept-Charset", "UTF-8");
            headerParams.add("Content-Type", "application/json; charset=UTF-8");
            headerParams.add("Content-Encoding", "UTF-8");
        } else {
            if (!headerParams.containsKey("Accept")) {
                headerParams.add("Accept", "application/json");
            }

            if (!headerParams.containsKey("Accept-Charset")) {
                headerParams.add("Accept-Charset", "utf-8");
            }

            if (!headerParams.containsKey("Content-Type")) {
                headerParams.add("Content-Type", "application/json; charset=UTF-8");
            }

            if (!headerParams.containsKey("Content-Encoding")) {
                headerParams.add("Content-Encoding", "UTF-8");
            }
        }

        return headerParams;
    }
     /**
     *
     * @param url
     * @params 可是是字符串例如:"1",也可以是json字符串{id:1,name:"2"}
     * @param perch url上面的占位符 https://mo.zeienrio.com/{version}/users/{user_id}  如这种
     * @param httpMethod  GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
     * @return
     */
    public static JSONObject httpRequestMethod(String url, String params, Map<String,Object> perch, HttpMethod httpMethod,MultiValueMap<String, String> headerParams , Boolean isNeedHeader){
        JSONObject result = new JSONObject();
        try{

            //需要头部才加,其他不需要
            if(isNeedHeader){
                headerParams = packHeader(headerParams);
            }

            HttpEntity<String> formEntity = new HttpEntity<String>(params, headerParams);

            ResponseEntity responseEntity =restTemplate.exchange(url, httpMethod, formEntity, String.class, perch);
            HttpStatus strVlaue = responseEntity.getStatusCode();
            if (strVlaue.value() == 200 || strVlaue.value() == 201 || strVlaue.value() == 202 ) {
                String body = (String)responseEntity.getBody();
                System.out.println(body);
                result = JSONObject.parseObject(body);

                //处理header,只有云计算Openstack才有这几个参数
                HttpHeaders  responseHeader = responseEntity.getHeaders();

                if(null != responseHeader){
                    List<String> subjectTokenList = responseHeader.get("X-Subject-Token");
                    List<String> authTokenList = responseHeader.get("X-Auth-Token");
                    if(null !=subjectTokenList && subjectTokenList.size()>0){
                        result.put("xSubjectToken",subjectTokenList.get(0));
                    }
                    if(null !=authTokenList && authTokenList.size()>0){
                        result.put("xAuthToken",authTokenList.get(0));
                    }
                }
                return result;
            }else{
                return null;
            }
        }catch (Exception e){
            e.printStackTrace();
             return null;
        }
    }

    /**
     * 请求服务器下载文件
     * @param url
     * @param params
     * @param perch
     * @param httpMethod
     * @return
     */
    public static ResponseEntity<byte[]> downLoad(String url, String params, Map<String,Object> perch,HttpMethod httpMethod){
        ClientHttpRequestInterceptor interceptor = new DownloadIntercetor();
        List<ClientHttpRequestInterceptor> list = new ArrayList<>();
        list.add(interceptor);

        restTemplate.setInterceptors(list);
        //请求头
        HttpHeaders httpHeaders = new HttpHeaders();

        HttpEntity<String> formEntity = new HttpEntity<String>(params, httpHeaders);
        ResponseEntity<byte[]> responseEntity =restTemplate.exchange(url, httpMethod, formEntity, byte[].class, perch);
        return responseEntity;
    }

    /**
     * 静态内部类
     */
    public static class DownloadIntercetor implements ClientHttpRequestInterceptor{
        private MediaType headerValue = MediaType.APPLICATION_OCTET_STREAM;

        public MediaType getHeaderValue() {
            return headerValue;
        }

        public void setHeaderValue(MediaType headerValue) {
            this.headerValue = headerValue;
        }

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
            List<MediaType> list = new ArrayList<>();
            list.add(headerValue);
            requestWrapper.getHeaders().setAccept(list);
            return execution.execute(requestWrapper,body);

        }
    }
 }

因为是通过工具类进行的处理,在没有处理下载请求的情况下,直接请求正常的获取数据的接口,就不会出现406的情况,但是只要请求的了下载文件的接口,再次请求获取正常数据的接口,那么就会出现406,这是因为请求了downLoad方法,内部类中的DownloadIntercetor,就会设置了统一的headers的Accept,那么通用的restTemplate,也已经被改了,所以就造成了,被请求方是:“application/json”,而请求方变成了:“application/octet-stream”,所以需要处理,在下载的时候用DownloadIntercetor拦截器,而在其他请求的时候,需要增加自定义的拦截器将Accept设置为application/json,

 /**
     * RestTemplate自定义拦截器设置
     * @param headers
     * @return
     * */
    private static List<ClientHttpRequestInterceptor> getClientHttpRequestInterceptor(MediaType headers){
        ClientHttpRequestInterceptor interceptor = new CloudDeskTopOrAppInterceptor(headers);
        List<ClientHttpRequestInterceptor> list = new ArrayList<>();
        list.add(interceptor);

        return list;
    }
    /**
     * 静态内部类
     */
    public static class CloudDeskTopOrAppInterceptor implements ClientHttpRequestInterceptor{
        private MediaType headerValue;
        public CloudDeskTopOrAppInterceptor(MediaType headerValue){
            this.headerValue = headerValue;
        }

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
            List<MediaType> list = new ArrayList<>();
            list.add(headerValue);
            requestWrapper.getHeaders().setAccept(list);
            return execution.execute(requestWrapper,body);

        }
    }

最后需要在httpRequestMethod方法的

restTemplate.setInterceptors(getClientHttpRequestInterceptor(MediaType.APPLICATION_JSON_UTF8));
//在这一句之前加上
ResponseEntity responseEntity =restTemplate.exchange(url, httpMethod, formEntity, String.class, perch);

这样就可以了,之前有过在在restTemplate.exchange方法之前直接设置,直接设置,没有新增自定义的拦截器,不过没有效果!特此记录!

你可能感兴趣的:(Java)