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方法之前直接设置,直接设置,没有新增自定义的拦截器,不过没有效果!特此记录!