“ 关于HTTP协议,对于我们开发来说应该是比较熟悉的,它是一种超文本传输协议,用于从万维网服务器传输超文本到本地浏览器的传送协议,它是使用TCP协议进行传输”
Http协议定义了很多与服务器交互的方法,其中GET,POST,PUT,DELETE是基本的有4种,通常我们最常用就是GET和POST请求了,在实际工作中,请求不会是一成不变的从前端发往后台,也有可能是后台访问其他系统的接口,此时Java模拟HTTP请求实现交互呢?
01
—
URL
在正式使用Java模拟HTTP请求前,我们先了解一下URL,我们知道通过HTTP协议定义的方法我们可以实现服务间的交互,这种交互依赖于HTTP使用的统一资源标识符(Uniform Resource Identifiers, URI),通过统一资源标识符就可以传输数据和建立连接。而URL是一种特殊类型的统一资源标识符,包含了用于查找某个资源的足够的信息。
比如说我们在浏览器地址栏输入http://www.baidu.com,然后浏览器就向我们呈现了百度的首页,这是一个什么样的过程?简单的说一下,浏览器首先向DNS服务器查询网站IP地址,浏览器得到IP地址后,会把用户输入的域名转化为HTTP服务请求,在请求之前TCP要进行三次握手建立链接,当服务器接收到请求后,返回网页数据,最后浏览器将这些信息组织成用户可以查看的网页形式。其中我们需要关注两点,首先是HTTP服务请求,然后是返回网页数据。
在上面分析完URL之后我们看一下GET和POST请求:
GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端,什么意思呢?我们分析这个这个URL:http://www.study,com:8080/api/article?id=1。这个URL包含了请求协议(http),域名(www.study.com),端口(8080),虚拟目录(/api/),文件名(article)和参数(id).也就说返回文章id为1的数据,但是如果需要传送大量数据的时候,不适合使用GET方式(浏览器对地址的字符限制)。
在GET方式不适用的时候我们就会用POST请求,POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,这样POST方式对传送的数据大小没有限制,而且也不会显示在URL中。
02
—
Java网络类
发送请求,就离不开网络,Java提供了网络类让你可以通过网络或者远程连接来实现应用。 其中URL类是我们最常用的,它允许Java程序设计人员打开某个特定URL连接,并对里边的数据进行读写操作以及对首部信息进行读写操作。而且,它还允许程序员完成其它的一些有关URL的操作
那我们看一下GET请求:其中connection.getInputStream()可以获取到响应数据流,然后通过输入流拿到响应的数据。
public static String sendGet(String url) {
String result = "";
BufferedReader in = null;
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
// 设置传递方式
connection.setRequestMethod("GET");
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
System.out.println(result);
return result;
}
为了方便我们使用Spring Boot搭建一个简单的服务用于访问,这个服务的目的是为了将参数进行加密,生成JWT身份令牌
@RequestMapping("getToken/{time}/{id}")
@ResponseBody
public String getToken(@PathVariable String time, @PathVariable String id) {
Map<String, String> map = new HashMap<String, String>();
map.put("timeStamp", System.currentTimeMillis() + "");
map.put("cv", id);
String param = JwtTokenUtil.createToken(30, map);
return param;
}
测试结果
Connected to the target VM, address: '127.0.0.1:54058', transport: 'socket'
null--->[HTTP/1.1 200]
Disconnected from the target VM, address: '127.0.0.1:54058', transport: 'socket'
Content-Length--->[177]
Date--->[Fri, 07 Dec 2018 11:30:53 GMT]
Content-Type--->[text/plain;charset=ISO-8859-1]
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0aW1lU3RhbXAiOiIxNTQ0MTgyMjUzMTgxIiwiY3YiOiIxIiwiZXhwIjoxNTQ2Nzc0MjUzLCJpYXQiOjE1NDQxODIyNTN9.HyOy4Uqc2PATL64S0YuefVVCx4XUV-ooEkhBLMQHxog
那么POST请求呢?
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
实际上JDK 库本身提供的功能还不够丰富和灵活,这时候我们可以了解一下HttpClient,它是 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包
小程序这周做了一次升级,目前正在审核中。主要是:
在首页的遮罩层增加了每日一句,放一些常用的知识点
增加个人中心,显示未读消息以及客服功能
选择题战绩增加解析
文章评论提供回复功能
(这个版本题库模块需要进行授权,文章和知识模块无需授权,原因是因为个人博客写小程序相关文章的时候无意把链接发出去了,然后有人恶意访问链接,所以后台增加了Token验证(也就是需要授权)。此外评论会进行审核,请小伙伴不要写一些恶意的语句,比如:alert("Hello World") )