【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求

Dear 丶 2023-10-02 16:17 155阅读 0赞

【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求
【HttpClient】在 SpringBoot 中使用 HttpClient 实现 HTTP 请求
【SpringBoot】使用 OkHttp 完成网络请求

在 SpringBoot 工程中,通过 HttpURLConnection 类来实现 HTTP 请求吧。

HttpURLConnection 是 JDK 自带的。

它的应用场景:在自己的工程中,你想调用第三方接口(外部接口)来获取数据,那么 HttpURLConnection 类就可以实现。接下来通过两个小案例来进行实现吧。

开发步骤:

  1. 先开发外部接口
  2. 再开发内部接口
  3. 在内部接口中,通过类 HttpURLConnection 去调用外部接口

为了测试方便,我这里就将外部接口、内部接口,全写在通过一个工程里面了哈。

1. 开发外部接口

1、新建一个 SpringBoot 工程

2、新开发 4 个接口:这4个接口就假定为外部接口。也就是说,是在我们工程中需要调用的接口

HttpController:两个接口用于 GET 请求的无参请求、有参请求;另外两个接口用于 POST 请求的无参请求、有参请求

  1. @RestController
  2. @RequestMapping("/http")
  3. public class HttpController {
  4. @Autowired
  5. private HttpService httpService;
  6. /// GET 请求/
  7. // 通过id获取用户信息
  8. @GetMapping("/getUserById")
  9. public UserVo getUserById(String id) {
  10. return httpService.getUserById(id);
  11. }
  12. // 获取所有用户信息
  13. @GetMapping("/listUsers")
  14. public List<UserVo> listUsers() {
  15. return httpService.listUsers();
  16. }
  17. /// POST 请求/
  18. // 通过id获取用户信息
  19. @PostMapping("/getUserVoById")
  20. public UserVo getUserVoById(String id) {
  21. return httpService.getUserById(id);
  22. }
  23. // 获取所有用户信息
  24. @PostMapping("/listUserList")
  25. public List<UserVo> listUserList() {
  26. return httpService.listUsers();
  27. }
  28. }

说明:

  1. 4个接口分别按照 getpost 请求区分
  2. get/post 请求中的两个接口:无参:查询所有用户信息;有参:按照用户id查询用户信息

HttpServiceImpl:这里我没有连接数据库,直接使用了假数据。

  1. @Service
  2. @Slf4j
  3. public class HttpServiceImpl implements HttpService {
  4. private static Map<String, UserVo> userVoMap;
  5. static {
  6. userVoMap = new HashMap<>();
  7. userVoMap.put("1", new UserVo("1", "zzc", "上海市"));
  8. userVoMap.put("2", new UserVo("2", "wzc", "北京市"));
  9. userVoMap.put("3", new UserVo("3", "wxc", "武汉市"));
  10. }
  11. @Override
  12. public UserVo getUserById(@RequestParam("id") String id) {
  13. return userVoMap.get(id);
  14. }
  15. @Override
  16. public List<UserVo> listUsers() {
  17. List<UserVo> userVos = new ArrayList<>();
  18. for (Map.Entry<String, UserVo> userVoEntry : userVoMap.entrySet()) {
  19. UserVo userVo = userVoEntry.getValue();
  20. userVos.add(userVo);
  21. }
  22. return userVos;
  23. }
  24. }

好了,到这就完成了我们外部接口的开发,接下来,就要通过类 HttpURLConnection 来调用这些接口了。

2. GET 请求

HttpController 类中再开一个接口:用于 get 请求测试

  1. @PostMapping("/httpUrlConnectionDoGet")
  2. public void httpUrlConnectionDoGet(@RequestBody HttpUrlConnectionVo httpUrlConnectionVo) {
  3. httpService.httpUrlConnectionDoGet(httpUrlConnectionVo);
  4. }

HttpUrlConnectionVo:请求Vo

  1. @Data
  2. public class HttpUrlConnectionVo {
  3. // 请求地址
  4. private String uri;
  5. // 请求参数
  6. private Map<String, String> params;
  7. // 编码
  8. private String encoding;
  9. }

HttpServiceImpl

  1. @Override
  2. public void httpUrlConnectionDoGet(@RequestBody HttpUrlConnectionVo httpUrlConnectionVo) {
  3. if (StringUtil.isBlank(httpUrlConnectionVo.getEncoding())) {
  4. log.error("【发送GET请求】失败,字符编码不能为空!");
  5. return;
  6. }
  7. HttpUrlConnectionUtil.doGet(httpUrlConnectionVo.getUri(), httpUrlConnectionVo.getParams(), httpUrlConnectionVo.getEncoding());
  8. }

HttpUrlConnectionUtil:URLConnection工具类

  1. @Slf4j
  2. @Component
  3. public class HttpUrlConnectionUtil {
  4. // 服务器ip
  5. public static final String IP = "http://localhost";
  6. // 端口
  7. public static final String PORT = ":8080";
  8. // GET请求接口带参数
  9. public static final String GET_URL_PARAMS = IP + PORT + "/http/getUserById";
  10. // GET请求接口不带参数
  11. public static final String GET_URL_NO_PARAMS = IP + PORT + "/http/listUsers";
  12. // POST请求接口带参数
  13. public static final String POST_URL_PARAMS = IP + PORT + "/http/getUserVoById";
  14. // POST请求接口不带参数
  15. public static final String POST_URL_NO_PARAMS = IP + PORT + "/http/listUserList";
  16. // 返回成功编码
  17. public static final Integer RESPONSE_CODE_SUCCESS = 200;
  18. // POST请求
  19. public static final String METHOD_POST = "POST";
  20. private static HttpUrlConnectionConfig httpUrlConnectionConfig = ApplicationContextHolder.getContext().getBean(HttpUrlConnectionConfig.class);
  21. // 通过HttpUrlConnection发起Get请求
  22. public static String doGet(String uri, Map<String, String> params, String encoding) {
  23. byte[] bytes = null;
  24. if (MapUtil.isEmpty(params)) {
  25. uri = GET_URL_NO_PARAMS;
  26. } else {
  27. uri = GET_URL_PARAMS;
  28. try {
  29. // 拼接参数
  30. bytes = transformRequestParams(params).getBytes(encoding);
  31. uri = uri + "?" + new String(bytes);
  32. } catch (UnsupportedEncodingException e) {
  33. log.error("【发送GET请求】字符集转换失败,失败信息为:{}", e);
  34. return null;
  35. }
  36. }
  37. log.info("【发送GET请求】请求地址为:{}", uri);
  38. URL url = null;
  39. HttpURLConnection connection = null;
  40. try {
  41. url = new URL(uri);
  42. // 建立连接
  43. connection = (HttpURLConnection)url.openConnection();
  44. httpUrlConnectionConfig.setConnectionProperty(connection);
  45. // 请求服务器
  46. connection.connect();
  47. // 获取服务器返回结果
  48. String responseData = getResponseData(connection, encoding);
  49. return responseData;
  50. } catch (MalformedURLException e) {
  51. log.error("【发送GET请求】创建URL失败,失败信息为:{}", e);
  52. } catch (IOException e) {
  53. log.error("【发送GET请求】创建连接失败,失败信息为:{}", e);
  54. }
  55. return null;
  56. }
  57. }

说明:

  1. 此类中的常量已经定义好了外部接口的 ip、端口号。由于是本机,所有是 localhost。SpringBoot应用默认启动端口号为 8080
  2. 此类中的常量也区分的 getpost 以及无参、有参
  3. 在静态方法中使用对象:httpUrlConnectionConfig.setConnectionProperty(connection);

MapUtil:判断 Map 是否为空

  1. public class MapUtil {
  2. public static boolean isEmpty(Map map) {
  3. return (map == null || map.isEmpty());
  4. }
  5. public static boolean isNotEmpty(Map map) {
  6. return !isEmpty(map);
  7. }
  8. }

transformRequestParams():将 Map 格式的参数转换为字符串

  1. // 转换请求参数
  2. public static String transformRequestParams(Map<String, String> params) {
  3. StringBuffer buffer = new StringBuffer();
  4. for (Map.Entry<String, String> entry : params.entrySet()) {
  5. buffer.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
  6. }
  7. if (buffer.length() > 0) {
  8. buffer.deleteCharAt(buffer.length() - 1);
  9. }
  10. return buffer.toString();
  11. }

HttpUrlConnectionConfig:HttpUrlConnection配置

  1. @Component
  2. public class HttpUrlConnectionConfig {
  3. public static final Integer CONNECTION_TIME_OUT = 10000;
  4. public static final Integer READ_TIME_OUT = 10000;
  5. // 设置连接时的属性
  6. public void setConnectionProperty(HttpURLConnection connection) {
  7. connection.setConnectTimeout(CONNECTION_TIME_OUT);
  8. connection.setReadTimeout(READ_TIME_OUT);
  9. connection.setRequestProperty("accept", "*/*");
  10. connection.setRequestProperty("connection", "close");
  11. connection.setRequestProperty("user-agent",
  12. "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");
  13. if (HttpUrlConnectionUtil.METHOD_POST.equals(connection.getRequestMethod())) {
  14. // 设置连接输出流为true,默认false (post 请求是以流的方式隐式的传递参数)
  15. connection.setDoOutput(true);
  16. // 设置连接输入流为true
  17. connection.setDoInput(true);
  18. // 表单数据
  19. connection.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
  20. }
  21. }
  22. }

ApplicationContextHolder:以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出 ApplicaitonContext

  1. @Component
  2. public class ApplicationContextHolder implements ApplicationContextAware {
  3. private static ApplicationContext context;
  4. @Override
  5. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  6. context = applicationContext;
  7. }
  8. public static ApplicationContext getContext() {
  9. return context;
  10. }
  11. public static Object getBean(String name) {
  12. return context != null ? context.getBean(name) : null;
  13. }
  14. public static <T> T getBean(Class<T> clz) {
  15. return context != null ? context.getBean(clz) : null;
  16. }
  17. public static <T> T getBean(String name, Class<T> clz) {
  18. return context != null ? context.getBean(name, clz) : null;
  19. }
  20. public static void addApplicationListenerBean(String listenerBeanName) {
  21. if (context != null) {
  22. ApplicationEventMulticaster applicationEventMulticaster = (ApplicationEventMulticaster)context.getBean(ApplicationEventMulticaster.class);
  23. applicationEventMulticaster.addApplicationListenerBean(listenerBeanName);
  24. }
  25. }
  26. }

getResponseData():获取响应信息

  1. // 获取响应信息
  2. public static String getResponseData(HttpURLConnection connection, String encoding) {
  3. BufferedReader in = null;
  4. StringBuffer result = new StringBuffer();
  5. StringBuffer errorMsg = new StringBuffer();
  6. try {
  7. // 调用成功
  8. if (RESPONSE_CODE_SUCCESS.equals(connection.getResponseCode())) {
  9. // 处理服务器响应
  10. in = new BufferedReader(new InputStreamReader(connection.getInputStream(), encoding));
  11. String line = null;
  12. while ((line = in.readLine()) != null) {
  13. result.append(line);
  14. }
  15. log.info("【发送GET请求】请求成功,返回结果为:{}", result.toString());
  16. return result.toString();
  17. } else {
  18. in = new BufferedReader(new InputStreamReader(connection.getErrorStream(), encoding));
  19. String line = null;
  20. while ((line = in.readLine()) != null) {
  21. errorMsg.append(line);
  22. }
  23. log.error("【发送GET请求】请求失败,失败信息为:{}", errorMsg.toString());
  24. return errorMsg.toString();
  25. }
  26. } catch (IOException e) {
  27. log.error("【发送GET请求】创建连接失败,失败信息为:{}", e);
  28. } finally {
  29. if (null != in) {
  30. try {
  31. in.close();
  32. } catch (IOException e) {
  33. log.error("【发送GET请求】关闭流失败,出现IO异常,异常信息为:{}", e);
  34. }
  35. }
  36. }
  37. return null;
  38. }

POSTMAN 调用接口:

1、GET 请求的无参:

在这里插入图片描述
查看控制台打印日志:
在这里插入图片描述
2、GET 请求的带参:
在这里插入图片描述
查看控制台打印日志:
在这里插入图片描述

3. POST 请求

HttpController:在 HttpController 类中再开一个接口:用于 post 请求测试

  1. @PostMapping("/httpUrlConnectionDoPost")
  2. public void httpUrlConnectionDoPost(@RequestBody HttpUrlConnectionVo httpUrlConnectionVo) {
  3. httpService.httpUrlConnectionDoPost(httpUrlConnectionVo);
  4. }

HttpServiceImpl

  1. @Override
  2. public void httpUrlConnectionDoPost(HttpUrlConnectionVo httpUrlConnectionVo) {
  3. if (StringUtil.isBlank(httpUrlConnectionVo.getEncoding())) {
  4. log.error("【发送POST请求】失败,字符编码不能为空!");
  5. return;
  6. }
  7. HttpUrlConnectionUtil.doPost(httpUrlConnectionVo.getUri(), httpUrlConnectionVo.getParams(), httpUrlConnectionVo.getEncoding());
  8. }

HttpUrlConnectionUtil.doPost()

  1. public static String doPost(String uri, Map<String, String> params, String encoding) {
  2. byte[] bytes = null;
  3. if (MapUtil.isEmpty(params)) {
  4. uri = POST_URL_NO_PARAMS;
  5. } else {
  6. uri = POST_URL_PARAMS;
  7. try {
  8. // 以字节的形式获取参数
  9. param = transformRequestParams(params);
  10. bytes = param.getBytes(encoding);
  11. } catch (UnsupportedEncodingException e) {
  12. log.error("【发送GET请求】字符集转换失败,失败信息为:{}", e);
  13. return null;
  14. }
  15. }
  16. log.info("【发送POST请求】请求地址为:{}", uri);
  17. URL url = null;
  18. HttpURLConnection connection = null;
  19. try {
  20. url = new URL(uri);
  21. // 1.建立连接
  22. connection = (HttpURLConnection)url.openConnection();
  23. // 【注意】这里的 POST 必须是大写,否则,会报错
  24. connection.setRequestMethod(METHOD_POST);
  25. httpUrlConnectionConfig.setConnectionProperty(connection);
  26. // 2.请求服务器
  27. connection.connect();
  28. // 3.拼接参数
  29. if (null != bytes && bytes.length > 0) {
  30. OutputStream out = connection.getOutputStream();
  31. out.write(bytes);
  32. out.close();
  33. }
  34. // 4.获取服务器返回结果
  35. String responseData = getResponseData(connection, encoding);
  36. return responseData;
  37. } catch (MalformedURLException e) {
  38. log.error("【发送POST请求】创建URL失败,失败信息为:{}", e);
  39. } catch (IOException e) {
  40. log.error("【发送POST请求】创建连接失败,失败信息为:{}", e);
  41. }
  42. return null;
  43. }

post 的有参、无参调用,跟 get 的一样,就是接口不同而已,可以自己试试吧。

好了,使用 HttpURLConnection 后台模拟实现 HTTP 请求就到这了。

发表评论

表情:
评论列表 (有 0 条评论,155人围观)

还没有评论,来说两句吧...

相关阅读