一、get和post的一些基础知识
get请求:
-
原理:get请求本质上是去数据库里面查资源;
-
表现形式:请求数据会依附在url只有,以?分割,参数与参数之间以&符号相连,请求参数最多只能是1024个字节;
-
提交形式:请求和header一起发出;
-
安全性:安全性低,参数明文传输。
post请求:
-
原理:post请求本质是向数据库提交数据,增删改操作;
-
表现形式:提交的数据放在http的body体内,http协议对post请求的参数大小没有限制,但是不排除各大浏览器自己会做限制;
-
提交形式:请求header先发出,收到服务器返回的response header后,body再发出;
-
安全性:相对get请求,post请求的请求参数放在body体内相对安全一些,涉及用户登录密码和金钱相关的数据要特别注意加密处理。
二、http协议和https协议
二者的区别:
- http协议:超文本传输协议,且信息是明文传输;若攻击者截取客户端和服务器之间的传输报文,就可以获取用户信息,不安全;
- https协议:是具有安全性的ssl加密传输协议,为客户端和服务器之间的通信加密,确保数据传输安全。
- http结构:http–tcp–ip;https结构:http–ssl–tcp–ip;
- http协议连接简单,是无状态的;https是有ssl+http协议构建的加密传输、身份认证的网络协议;
- http协议的端口是80;https协议的端口是443;
- http证书申请免费,https证书需要到ca申请,需要交费。
三、Java-HTTPclient官方网站
2.1 官网地址:
http://hc.apache.org/httpcomponents-client-4.5.x/quickstart.html
2.2 eclipse中maven工程在pom.xml中配置HTTPclient依赖
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
四、java发送get请求
- A. 定义一个HTTPClients类的对象client,用来执行发送请求操作。类似于是一个浏览器的driver,client执行完发送请求的操作后,服务端返回的cookie(和session)信息会存储在client中;
- A.1 取cookie过程需要在定义client时调用另一个类方法,即方法:HttpClients.custom()方法,它的返回值类型是HttpClientBuilder,最后通过研究这个源码类使用以下两行代码得到CookieStore对象存储服务器返回的session值,这个值存放在cookie中;
CookieStore cookieStore = new BasicCookieStore();
client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
如果想要输出cookie信息,则需要注意两点:
1、输出cookie信息的操作要在执行请求后,即服务器返回结果后,在关闭response和client对象之前;
2、通过cookieStore.getCookies()方法得到的是一个List对象,数组的输出通过for循环即可得到结果。
- B. 定义一个HTTPGet类的对象httpGet,用来携带需要发送的信息,例如请求url、请求头header信息、请求超时等信息;
- B.1 请求url:初始化时,调用HttpGet类的构造方法时传参实现。get请求url是接口地址和请求参数拼接组成,代码中第5行;
- B.2 请求头header信息:通过拿到的httpGet对象,向上转型到HttpMessage源码类,调用HttpMessage源码类中的setHeader(final String name, final String value)方法,该方法已经在子类中被覆写,子类是:AbstractHttpMessage;
- B.3 请求超时 通过HttpGet对象向上转型调用父类HttpRequestBase源码类中的setConfig(final RequestConfig config)方法添加到httpGet对象中,其中setConfig()方法中传参是RequestConfig类型,通过研究RequestConfig这个源码类就可设置成功超时时间,调用的是setConnectionRequestTimeout(final int connectionRequestTimeout)方法;
- C. 准备好发送请求的数据后,使用client.execute(httpGet)发送请求,得到对象response,是CloseableHttpResponse类型,我们想要是String或者Json类型结构的数据,还没达到目标;
- D. 判断response.getStatusLine().getStatusCode()是否返回的时200,当是200时证明服务器返回正常,我们再通过response.getEntity()方法得到一个HttpEntity类型的返回对象entity;
- E. 最后通过EntityUtils工具类中的EntityUtils.toString(entity, “utf-8”)方法把上一步得到的entity对象转化成String类型,返回结果;
- F. 最最后,我们要恢复环境执行response.close()和client.close()。
简单封装后的发送get请求整个过程代码如下:
public static void sendGet(String url, String param) throws Exception {
String result = null;
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
String finUrl = url + "?" + param;
try {
client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(finUrl);
//设置请求头
httpGet.setHeader("Content-Type", "application/json; charset=utf-8");
httpGet.setHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36");
//设置请求超时
Builder builder = RequestConfig.custom();
builder.setConnectionRequestTimeout(3000);
RequestConfig config = builder.build();
httpGet.setConfig(config);
httpGet.setConfig(RequestConfig.custom().setConnectionRequestTimeout(3000).build());
response = client.execute(httpGet);
int code = response.getStatusLine().getStatusCode();
if (code == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "utf-8");
}else {
result = "服务器状态码为:" + code + " ,请检查接口地址和请求参数。";
}
}finally {
response.close();
client.close();
}
return result;
}
五、java发送post请求
- A. 定义一个HTTPClients类的对象client,用来执行发送请求操作。类似于是一个浏览器的driver,client执行完发送请求的操作后,服务端返回的cookie(和session)信息会存储在client中;
- B. 定义一个HTTPGet类的对象httpPost,用来携带需要发送的信息,例如请求url、请求头header信息、请求超时等信息;
- C. 准备请求参数,post请求参数存放在请求body体内,如果使用官网方法,需要传参为NameValuePair类型的数据,即官网示例如下:
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("username", "vip"));
nvps.add(new BasicNameValuePair("password", "secret"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
因为我们正常提供的测试case,在param字段中一般存String类型,所以找传String类型的请求参数,放到httpPost对象中(通过httpPost.setEntity()方法),携带发送请求。经过研究发现httpPost.setEntity()方法的入参是HttpEntity源码类的对象,但是HttpEntity是个接口,只能通过实例化子类来得到父类对象,找到StringEntity源码类,发现使用这个源码类中的其中一个构造方法,可以传String类型的参数,new子类通过向上转型,从而得到HttpEntity的对象,到此我们把sendPost方法中的String param字段添加到了httpPost对象内;
- D. 准备好发送请求的数据后,使用client.execute(httpPost)发送请求,得到对象response,是CloseableHttpResponse类型,我们想要是String或者Json类型结构的数据,还没达到目标;
- E. 判断response.getStatusLine().getStatusCode()是否返回的时200,当是200时证明服务器返回正常,我们再通过response.getEntity()方法得到一个HttpEntity类型的返回对象entity;
- F. 最后通过EntityUtils工具类中的EntityUtils.toString(entity, “utf-8”)方法把上一步得到的entity对象转化成String类型,返回结果;
- G. 最最后,我们要恢复环境执行response.close()和client.close()。
简单封装后的发送post请求整个过程代码如下:
public static String sendPost(String url, String param) throws Exception {
String result = null;
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
try {
client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
//设置请求头
httpPost.setHeader("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148");
httpPost.setHeader("Content-Type", "application/json");
//设置请求超时
Builder builder = RequestConfig.custom();
builder.setConnectionRequestTimeout(3000);
RequestConfig config = builder.build();
httpPost.setConfig(config);
httpPost.setConfig(RequestConfig.custom().setConnectionRequestTimeout(3000).build());
//设置post请求参数
// List<NameValuePair> nvps = new ArrayList<NameValuePair>();
// BasicNameValuePair bnvp = new BasicNameValuePair(null, null);
// 直接添加NameValuePair类型的数据 遇到一级value下又有多级数据时也是直接写入吗?例如:"h_ids": {"idfa": "0CB4E1A5-1782-4F31-8B30-0218453BBCBE"}
// nvps.add(new BasicNameValuePair("name", "zhaoliu"));
// httpPost.setEntity(new UrlEncodedFormEntity(nvps));
//入参是HttpEntity类型,HTTPEntity是个接口,需要通过子类实例化得到父类对象,找HTTPEntity的实现类,StringEntity
// httpPost.setEntity(HTTPEntity httpEntity);
httpPost.setEntity(new StringEntity(param, "utf-8"));
// 执行发送请求操作
response = client.execute(httpPost);
int code = response.getStatusLine().getStatusCode();
if (code == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "utf-8");
}else {
result = "服务器状态码为:" + code + " ,请检查接口地址和请求参数。";
}
}finally {
response.close();
client.close();
}
return result;
}
六、总结
6.1 不管发送post请求还是get请求,都需要先定义CloseableHttpClient的对象client。client对象可以生成一个CookieStore的对象管理和存储header的cookie和服务器返回的session信息,即cookie和session信息是在client对象这里操作的;
6.2 得到HttpGet或者HttpPost对象后,我们要设置的请求超时、请求header数据都是在这一步生成和操作的;
6.3 get请求的参数通过拼接即可实现,但post请求的请求参数是在body体内的,要通过httpPost.setEntity(new StringEntity(param, “utf-8”))代码绑定到HttpPost的对象上;
6.4 以上三步准备好之后,通过client.excute(httpPost) / client.excute(httpGet)拿到CloseableHttpResponse类型的一个返回值,我们初步拿到了服务器的返回结果;
6.5 对服务器返回结果做处理,通过response.getEntity()方法把返回结果转化成HttpEntity类型,最后通过EntityUtils工具类中的toString()方法把服务器返回的结果转化成我们常见的String类型;
6.6 最后就是善后工作,关闭response对象,关闭client对象。
赶快自己去实验一下吧!
中间的一些源码转换没有详细记录,哪里看不太懂欢迎和我交流!