java.net的HttpUrlConnection功能

你好

今天,我将尝试讨论如何使用JRE库中的URLConnection发送请求并从HTTP服务器读取响应。

我们目前正在在线学习Java。 我们整个团队都使用Slack进行工作和沟通。 有关用户的信息,我们使用Slack API。 为了避免长时间谈论API本身(这是另一篇文章的主题),我将简短地说一遍:Slack API是基于HTTP协议构建的,要获取有关用户的信息,您需要发送一个带有URI的请求,其中URI中必须有一个方法名称,该API必须来自API到主机地址api。 slack.com以下是一些方法的列表:
  • users.list
  • chat.postMessage
  • 对话创建
  • files.upload
  • 即时开放

要获得用户列表,您需要users.list方法。 我们在请求主体中形成URI-/api/users.list ,在应用程序/ x-www-form-urlencoded形式中应该有一个身份验证令牌,也就是说,请求应该看起来像这样(但是会有一个细微差别会更低):

GET /users.list HTTP/1.1 Content-Type: application/x-www-form-urlencoded token=xoxp-1234567890-098765-4321-a1b2c3d4e5 


我知道Apache HttpComponents库,但是出于研究目的,我们将使用标准Java 8库中可用的工具,即java.net.URLConnection的实现。

要获取URLConnection实体,您需要使用java.net.URL类的对象,其构造函数采用String类型,在该类型中,除所有内容外,还必须指定协议-在我们的示例中为https。

收到URL实体后,我们调用openConnection()方法,该方法将返回HttpsUrlConnection实体。

 String url = “https://slack.com/api/users.list”; URLConnection connection = new URL(url).openConnection(); 

在这种情况下,您需要处理或引发MalformedUrlException和IOException。

之后,连接变量将存储对HttpsUrlConnectionImpl对象的引用。 默认情况下,将生成一个GET请求,要添加Header,我们使用setRequestProperty()方法,该方法接受键和值。 我们需要在此处安装一个Content-Type,其值为application / x-www-form-urlencoded 。 好吧,我们做到了!
 connection.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”); 

现在只剩下通过写我们的令牌和限制到正文中来发送请求了。 为此,请使用setDoOutput()方法将连接对象的doOutput字段设置为true;

 connection.setDoOutput(true); 

接下来,最有趣的部分-您需要以某种方式将我们的请求正文传递给OutputStream。 我们将使用OutputStreamWriter:

 OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); 

有一个警告:在我们调用getOutputStream()方法之后,由于GET不提供请求正文,因此请求方法更改为POST,但是好处是,松弛对方法没有严格限制,因此一切都很好。 因此,GET请求应如下所示:
 GET /users.list?token=xoxp-1234567890-098765-4321-a1b2c3d4e5&limit=100 HTTP/1.1 Content-Type: application/x-www-form-urlencoded 

但是我没有开始重做。 相反,我们的请求结果如下:

 POST /users.list HTTP/1.1 Content-Type: application/x-www-form-urlencoded token=xoxp-1234567890-098765-4321-a1b2c3d4e5 

(*一些标头是由HttpsUrlConnection自己设置的,此处不存在)

因此,要编写请求主体,请使用write();。
 String reqBody = “token=xoxp-1234567890-098765-4321-a1b2c3d4e5&limit=100”; writer.write(reqBody); writer.close(); 

之后,我们的请求将被发送,我们可以读取收到的响应。 在接收InputStream之前关闭OutputStream或执行flush()很重要,否则数据将不会离开缓冲区(或者,您可以使用PrintStream-在println()方法中,默认调用flush())。 为了阅读,我使用了BufferedReader:
 StringBuilder respBody = new StringBuilder(); BufferedReader reader = new BufferedReader(connection.getInputStream()); reader.lines().forEach(l -> respBody.append(l + “\r\n”); reader.close(); 

(*使用行()获得输出流; \ r \ n-CRLF字符-插入到新行的过渡)

并且,如果我们成功进行身份验证,则respBody变量应存储来自服务器的响应,在本例中为服务器的JSON对象。 之后,可以将其发送到下一个处理阶段。

经过一些优化后,一切看起来像这样:

 package main.java.com.bilichenko.learning; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.util.Optional; import java.util.stream.Collectors; public class SlackClient { private static final String HOST = "https://api.slack.com"; private static final String GET_USERS_URI = "/api/users.list"; private static final String TOKEN = "xx-ooo-YOUR-TOKEN-HERE"; public static void main(String[] args) throws IOException { SlackClient slackClient = new SlackClient(); System.out.println(slackClient.getRawResponse(HOST + GET_USERS_URI, "application/x-www-form-urlencoded", "token=" + TOKEN).orElse("no response")); } public Optional<String> getRawResponse(String url, String contentType, String requestBody) throws MalformedURLException, IOException { HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setRequestProperty("Content-Type", contentType); connection.setConnectTimeout(10000); connection.setRequestMethod("POST"); connection.setDoOutput(true); try(OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) { writer.write(requestBody); } if (connection.getResponseCode() != 200) { System.err.println("connection failed"); return Optional.empty(); } try(BufferedReader reader = new BufferedReader( new InputStreamReader(connection.getInputStream(), Charset.forName("utf-8")))) { return Optional.of(reader.lines().collect(Collectors.joining(System.lineSeparator()))); } } } 

希望对您有所帮助!

Source: https://habr.com/ru/post/zh-CN459080/


All Articles