SpringBoot 使用 RestTemplate 出现乱码


1. 问题描述

项目中用到了百度的AI接口,我们使用Spring封装的RestTemplate 工具进行Http请求,出现了乱码问题,百度API文档写的是该接口响应的内容是UTF-8编码。

如上图所示,百度AI接口返回的信息并没有指定编码(其实是UTF-8的编码格式,只是没指定)。所以Spring Boot就以默认的ISO-8859-1对返回的数据流进行了编码,转换为String,这时其实已经乱码了,接着因为我的开发环境是UTF-8的,所以打印出来全是乱码。转码过程大概是这样的:(UTF-8—>字节数据—>ISO-8859-1—>UTF-8

{
    "log_id":7806616030292411514,
    "items":[
        {
            "sentiment":2,
            "abstract":"<span>东西很好</span>吃",
            "prop":"东西",
            "begin_pos":0,
            "end_pos":12,
            "adj":"很好"
        },
        {
            "sentiment":2,
            "abstract":"<span>服务也很不错</span>",
            "prop":"服务",
            "begin_pos":0,
            "end_pos":18,
            "adj":"好"
        }
    ]
}

2. 简单处理

对返回信息进行编码转换。转换方法:对响应结果result进行ISO-8859-1解码和UTF-8编码即可。转码过程大概是这样的:(UTF-8—>字节数据—>ISO-8859-1—>字节数据—>UTF-8

//工具类中注入静态成员属性。
private static RestTemplate restTemplate;
@Autowired
public void setRestTemplate(RestTemplate restTemplate) {
     BaiduUtils.restTemplate = restTemplate;
}
//方法代码
String url = SERVER_COMMENT_TAG.replace("{TOKEN}", token);
HttpHeaders headers = new HttpHeaders();
MediaType mediaType = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(mediaType);
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", type);
jsonObject.put("text", comment);
HttpEntity<String> paramEntity = new HttpEntity<>(jsonObject.toJSONString(), headers);
//这里提交的参数是String类型的
String baiduResult = restTemplate.postForObject(url, paramEntity, String.class);
//这里进行编码转换
String result = new String(baiduResult.getBytes("ISO-8859-1"), "UTF-8");
log.info(result );

打印结果

{
    "log_id":7806616030292411514,
    "items":[
        {
            "sentiment":2,
            "abstract":"<span>东西很好</span>吃",
            "prop":"东西",
            "begin_pos":0,
            "end_pos":12,
            "adj":"很好"
        },
        {
            "sentiment":2,
            "abstract":"<span>服务也很不错</span>",
            "prop":"服务",
            "begin_pos":0,
            "end_pos":18,
            "adj":"好"
        }
    ]
}

3. 源码解读

RestTemplate类的部分源码:

public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {

	private static boolean romePresent;
	private static final boolean jaxb2Present;
	private static final boolean jackson2Present;
	private static final boolean jackson2XmlPresent;
	private static final boolean jackson2SmilePresent;
	private static final boolean jackson2CborPresent;
	private static final boolean gsonPresent;
	private static final boolean jsonbPresent;

	static {
		ClassLoader classLoader = RestTemplate.class.getClassLoader();
		romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
		jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
		jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)  && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
		jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
		jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
		jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
		gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
		jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
	}

	private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();

	//。。。。。。省略代码
	
	/**
	 * 使用默认设置创建 RestTemplate 的新实例。
	 * 默认初始化 HttpMessageConverter HttpMessageConverters。
	 */
	public RestTemplate() {
		this.messageConverters.add(new ByteArrayHttpMessageConverter());
		// 处理 String 类型的参数
		this.messageConverters.add(new StringHttpMessageConverter());
		this.messageConverters.add(new ResourceHttpMessageConverter(false));
		try {
			this.messageConverters.add(new SourceHttpMessageConverter<>());
		}
		catch (Error err) {
			// 忽略没有TransformerFactory实现可用的情况
		}
		this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
		if (romePresent) {
			this.messageConverters.add(new AtomFeedHttpMessageConverter());
			this.messageConverters.add(new RssChannelHttpMessageConverter());
		}
		if (jackson2XmlPresent) {
			this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
		}
		else if (jaxb2Present) {
			this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
		}
		if (jackson2Present) {
			// 处理 JSON 类型数据
			this.messageConverters.add(new MappingJackson2HttpMessageConverter());
		}
		else if (gsonPresent) {
			this.messageConverters.add(new GsonHttpMessageConverter());
		}
		else if (jsonbPresent) {
			this.messageConverters.add(new JsonbHttpMessageConverter());
		}
		if (jackson2SmilePresent) {
			this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
		}
		if (jackson2CborPresent) {
			this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
		}
		this.uriTemplateHandler = initUriTemplateHandler();
	}
	//。。。。。。省略代码
}

通过跟踪断点,简单分析下RestTemplate内部源码,发现以 JavaBean,Map,JSONObject 格式分别提交数据时,RestTemplate底层均采用了MappingJackson2HttpMessageConverter来处理请求。而以String格式提交数据时,底层其实采用的是StringHttpMessageConverter来处理请求。

打开StringHttpMessageConverter源码,发现该构造器默认的字符集是ISO-8859-1

public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {

	/**
	 * 转换器使用的默认字符集。
	 */
	public static final Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
	@Nullable
	private volatile List<Charset> availableCharsets;
	private boolean writeAcceptCharset = true;
	/**
	 * 使用"ISO-8859-1"作为默认字符集的默认构造函数。
	 * @see #StringHttpMessageConverter(Charset)
	 */
	public StringHttpMessageConverter() {
		this(DEFAULT_CHARSET);
	}
	/**
	 * 如果所请求的内容类型没有指定,则接受要使用的默认字符集的构造函数。
	 */
	public StringHttpMessageConverter(Charset defaultCharset) {
		super(defaultCharset, MediaType.TEXT_PLAIN, MediaType.ALL);
	}
	//。。。。。。省略代码
}

4. 解决方法

直接在List<HttpMessageConverter<?>>中对StringHttpMessageConverter设置编码,并进行覆盖。

public class RestUtil {
	private final static RestTemplate restTemplate;
    static {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        //做一些其他设置
        requestFactory.setConnectTimeout(3000);
        requestFactory.setReadTimeout(3000);
        restTemplate = new RestTemplate(requestFactory);
        //解决乱码问题,在列表中的对应位置直接覆盖
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    }
    //工具方法
}
public class RestUtil {
	private final static RestTemplate restTemplate;
    static {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        //做一些其他设置
        requestFactory.setConnectTimeout(3000);
        requestFactory.setReadTimeout(3000);
        restTemplate = new RestTemplate(requestFactory);
        //解决乱码问题,遍历寻找,进行覆盖
        List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
	    for (HttpMessageConverter<?> httpMessageConverter : list) {
	        if(httpMessageConverter instanceof StringHttpMessageConverter) {
	            ((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(StandardCharsets.UTF_8);
	            break;
	        }
	    }
    }
    //工具方法
}

RestTemplate提供的构建器RestTemplateBuilder也提供了设置MessageConverter的方法,所以可以在构建时设置特殊的编码就可以解决问题了。

public class RestUtil {
	private final static RestTemplate restTemplate;
	static {
	    //解决乱码问题,遍历寻找,进行覆盖
	    StringHttpMessageConverter messageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
	    //添加额外的HttpMessageConverter,在构建器上配置的任何转换器都将替换RestTemplate的默认转换器。
	    restTemplate = new RestTemplateBuilder().additionalMessageConverters(messageConverter).build();
	}
	//工具方法
}

5. 简单使用

RestTemplate底层是通过HttpURLConnection实现的。
(1)getForObject

RestTemplate restTemplate = new RestTemplate(https://blog.csdn.net/mryang125/article/details/80955558);
String url = "http://localhost:8080/user/{id}";
UserVo userVo = restTemplate.getForObject(url, UserVo.class, id);

第一个参数表示URL,第二个参数表示返回类型,第三个参数表示URI中对应的参数,是一个可变长参数,可按顺序写多个参数。

(2)getForEntity

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/users/{userName}/{note}/{start}/{limit}";
//使用map封装多个参数
Map<String, Object> params = new HashMap<>();
params.put("userName", userName);
params.put("note", note);
params.put("start", start);
params.put("limit", limit);
ResponseEntity<List> responseEntity = restTemplate.getForEntity(url, List.class, params);
List<UserVo> userVos = responseEntity.getBody();

(3)postForObject

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user";
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
//创建请求实体对象
HttpEntity<UserVo> request = new HttpEntity<>(newUserVo, headers);
User user = restTemplate.postForObject(url, request, User.class);

(4)postForEntity

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user";
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
//创建请求实体对象
HttpEntity<UserVo> request = new HttpEntity<>(newUserVo, headers);
//请求服务器
ResponseEntity<User> responseEntity = restTemplate.postForEntity(url, request, User.class);
//获取响应体
User user = responseEntity.getBody();
//获取响应头
HttpHeaders respHeaders = responseEntity.getHeaders();
//获取响应属性
List<String> success = respHeaders.get("success");
//获取响应状态码
int statusCode = responseEntity.getStatusCodeValue();

(5)delete

RestTemplate restTemplate = new RestTemplate();
restTemplate.delete("http://localhost:8080/use/{id}", id);

(6)exchange
RestTemplate还提供了一个exchange方法,该方法比上面的方法灵活,可以通过制定参数实现各种Http请求。下面列出Spring提供的八种方法。

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType) throws RestClientException;

<T> ResponseEntity<T> exchange(String url,HttpMethod method, HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType) throws RestClientException;

<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType) throws RestClientException;

<T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, ParameterizedTypeReference<T> responseType) throws RestClientException;

下面写一个使用例子:

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user";
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
//创建请求实体对象
HttpEntity<UserVo> request = new HttpEntity<>(newUserVo, headers);
//请求服务器
ResponseEntity<User> responseEntity = restTemplate.exchange(url,  HttpMethod.POST, request, User.class);
//获取响应体
User user = responseEntity.getBody();
//获取响应头
HttpHeaders respHeaders = responseEntity.getHeaders();
//获取响应属性
List<String> success = respHeaders.get("success");
//获取响应状态码
int statusCode = responseEntity.getStatusCodeValue();

//获取资源
String url1 = "http://localhost:8080/user/{id}";
ResponseEntity<User> responseEntity1 = restTemplate.exchange(url1,  HttpMethod.GET, null, User.class, id);
//获取响应体
User user1 = responseEntity1.getBody();

6. 使用泛型接收响应示例

这里添加一个返回类型中泛型的使用方法:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

//创建请求实体对象,这里将参数转换为JSON字符串了
HttpEntity<String> request = new HttpEntity<>(paramJsonStr, headers);
//请求服务器
RestTemplate restTemplate = new RestTemplate();
String url = "http://www.baidu.com/task";
ResponseEntity<String> responseEntity = null;
try {
	//统一使用String接收响应,再用Jackson转为对应的实体类
    responseEntity = restTemplate.postForEntity(url, request, String.class);
//这里使用try...catch是因为有可能因为网络原因出现错误,RestClientException 的子类 ResourceAccessException 异常
} catch (RestClientException e) {
    e.printStackTrace();
}

if (responseEntity != null) {
    //获取响应体
    String body = responseEntity.getBody();
    //使用Jackson转为对应的实体类,这里的Result中使用到了泛型,用来应对多种格式
    ObjectMapper mapper = new ObjectMapper();
    Result<Ret> result = mapper.readValue(body, new TypeReference<Result<Ret>>() {});
    if (result != null) {
    	//使用了泛型,不同的请求这里就可以获取到不同类型的data
        Ret data = result.getData();
        System.out.println("data : " + data);
    }
}
@Data
public class Result<T> {
    private String logid;
    private T data;
    private Integer status;
    private String message;
    private Double st;
    private Double crt;
}
@Data
public class Ret {
    private Boolean ret;
    private String photoId;
}

RestTemplate 执行时报的异常信息,对方并没有接收到请求,应该是域名解析错误了,网络不通导致的。

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://control.aijiapin.com/jiapin/api/sign/ctrl/add-cloud-task": control.aijiapin.com; nested exception is java.net.UnknownHostException: control.aijiapin.com

	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:785)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711)
	at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:468)
	at com.example.demo.miaoxiuyun.ApiTest.addTaskApi(ApiTest.java:55)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.util.ArrayList.forEach(ArrayList.java:1259)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.util.ArrayList.forEach(ArrayList.java:1259)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.net.UnknownHostException: control.aijiapin.com
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:196)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:162)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:394)
	at java.net.Socket.connect(Socket.java:606)
	at java.net.Socket.connect(Socket.java:555)
	at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
	at sun.net.www.http.HttpClient.<init>(HttpClient.java:242)
	at sun.net.www.http.HttpClient.New(HttpClient.java:339)
	at sun.net.www.http.HttpClient.New(HttpClient.java:357)
	at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1226)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1162)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1056)
	at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:990)
	at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:76)
	at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
	at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:776)
	... 68 more
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值