HTTP Server 也是我们常说的Web服务器
在网络中传递的信息都是以【二进制】形式存在的,接收方在接收信息后需要把二进制数据编译为原数据。
弊端:HTTP协议无法实现服务器主动向客户端发起消息。
http服务器需要
1、可以接收来自浏览器发送的Http请求协议包,并自动对Http请求协议包内容解析
2、并将定位的文件内容给写入到Http写入到HTTP响应协议包
在基于B/S结构下,互联网通信过程中,所有在网络中传递信息都是保存在HTTP网络协议包
浏览器 向 WEB服务器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
HTTP请求协议包自上而下划分为4个空间:请求行、请求头部、空行和请求数据4部分组成。
请求行主要提供:请求地址、请求方式、HTTP 协议版本字段
Get方式参数存放在请求数据包的请求行的URI字段中,
以?开始,以param=value¶me2=value2的形式附加在URI字段之后
请求头部:格式为“属性名:属性值”,每行一对。请求头部通知服务器有关于客户端请求的信息,常见的如下:
Authorization:常用于传递身份验证凭证,如基本认证(Basic Authentication)或令牌(Token)。服务器可以根据这些凭证对请求进行身份验证,以确定是否允许访问受保护的资源。
Content-Type:指定了请求体中数据的格式类型,如JSON、表单数据等。服务器可以根据Content-Type来正确解析请求体中的数据。
其他典型的请求头还有:
● User-Agent:产生请求的浏览器和操作系统信息;
● Accept:客户端可识别的响应内容类型列表;星号 “ * ” 用于按范围将类型分组,用 “ */* ” 指示可接受全部类型,用“ type/* ”指示可接受 type 类型的所有子类型;
● Accept-Language:客户端可接受的自然语言;
● Accept-Encoding:客户端可接受的编码压缩格式;
● Accept-Charset:可接受的应答的字符集;
● Host:请求的主机名,允许多个域名同处一个IP 地址,即虚拟主机;
● connection:连接方式(close 或 keepalive);
● Cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie;
● Referer:指示了当前请求是从哪个URL页面发起的,可以帮助服务器识别请求的来源。
---------------------------------------
x-forwarded-for:是一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址
X-Forwarded-For 请求头格式
X-Forwarded-For: client, proxy1, proxy2
可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP(用户真实 IP),然后是每一级代理设备的 IP。
public static String getIpAddr(HttpServletRequest request) { if (request == null) { return "unknown"; } String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Forwarded-For"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Real-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; }
CONTENT_TYPE
空白行:没有任何内容。是用来区分"请求头"和"请求体"的
请求体:如果请求方式是post,那么请求参数信息会保存到请求体中
WEB服务器 向 浏览器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
HTTP状态码
Content-Type:指定浏览器采用对应编译器对响应体二进制数据进行解析
空白行:区分"响应头"和"响应体"
响应体:可能是被访问静态资源文件内容,可能是动态资源文件的运行结果
HTTP 请求可以使用多种请求方法。
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。
HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
1 | GET | 请求指定的页面信息,并返回实体主体。 |
2 | HEAD | 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头 |
3 | POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。 |
4 | PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 |
5 | DELETE | 请求服务器删除指定的页面。 |
6 | CONNECT | HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。 |
7 | OPTIONS | 允许客户端查看服务器的性能。 |
8 | TRACE | 回显服务器收到的请求,主要用于测试或诊断。 |
9 | PATCH | 是对 PUT 方法的补充,用来对已知资源进行局部更新 。 |
HttpClient 是Apache HttpComponents 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
spring boot集成HttpClient
org.apache.httpcomponents
httpclient
如果是maven工程,引入如下maven依赖
org.apache.httpcomponents.client5
httpclient5
5.1.1
在 HttpClient 中把响应封装成了 CloseableHttpResponse
对象,在此对象中可以获取如下数据:
HttpClient 提供了 EntityUtils
工具类,可以很好的把 响应的 HttpEntity 转换为 字节数组或者字符串
// 转换为字符串
EntityUtils.toString(response.getEntity());
// 转换为字节数组
EntityUtils.toByteArray(response.getEntity());
调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
GET请求的所有参数是直接拼接在 URL 后面的,在浏览器地址栏中可见。
GET请求url编码
使用GET请求时会将参数附加到URL的查询字符串中,以便将其发送给服务器。但是GET请求只接受ASCII字符作为参数值。
解决办法:
GET请求会把参数进行URL编码(也称为百分号编码或URL转义),以确保特殊字符不会干扰URL结构。
如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
public static void main(String[] args) throws Exception {
//获取默认配置的 HttpClient
CloseableHttpClient httpclient = HttpClients.createDefault();
//设置单个请求的配置信息
RequestConfig requestConfig = RequestConfig.custom()
// 设置连接超时时间
.setConnectTimeout(Timeout.of(3000, TimeUnit.MILLISECONDS))
// 设置响应超时时间
.setResponseTimeout(3000, TimeUnit.MILLISECONDS)
// 设置从连接池获取链接的超时时间
.setConnectionRequestTimeout(3000, TimeUnit.MILLISECONDS)
.build();
// 请求路径及参数
String name = URLEncoder.encode("张三", "utf-8");
String url = "http://localhost:10010/user/params?age=20&name=" + name;
HttpGet httpget = new HttpGet(url);
httpget.setConfig(requestConfig);
// 调用 HttpClient 的 execute 方法执行请求
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
System.out.println(result);
} finally {
response.close();
}
}
通过 URIBuilder 构建请求路径
使用POST请求时,参数通过HTTP消息体进行传输,并不会直接显示在URL上。POST支持多种编码方式。具体的数据格式和编码方式由 Content-Type
字段确定。服务端会根据 Content-Type 字段使用不同的方式对请求体进行解析。
最常用的POST数据编码方式是 application/x-www-form-urlencoded ,它与GET相似,也会对非ASCII字符和特殊字符进行URL编码。
这种方式下,参数按照键值对形式出现在消息正文中,并用&符号连接起来,同时以 = 分隔键和值,
HTTP 中的 POST 请求的数据是包含在请求体中的。在 HttpClient 中 POST 请求发送数据是通过,调用
HttpPost
类的setEntity(HttpEntity entity)
方法设置消息内容的public static void main(String[] args) throws Exception { // 创建 ContentType 对象为 form 表单模式 ContentType contentType = ContentType.create("application/x-www-form-urlencoded", StandardCharsets.UTF_8); String url = "http://localhost:10010/user/body"; HttpPost httpPost = new HttpPost(url); //设置请求头,添加到 HttpPost 头中 httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType); //HttpPost请求 要传的参数 这里先将参数封装起来 List
params = new ArrayList<>(); params.add(new BasicNameValuePair("name", "张三")); params.add(new BasicNameValuePair("age", "20")); //这一步才是 为post 请求设置参数 这是创建表单的实体对象 设置当前参数的编码格式 //设置请求数据,把HttpEntity 设置到 HttpPost 中 httpPost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); //获取默认配置的 HttpClient CloseableHttpClient httpclient = HttpClients.createDefault(); //调用 HttpClient 的 execute 方法执行请求 CloseableHttpResponse response = httpclient.execute(httpPost); try { HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity); EntityUtils.consume(entity); System.out.println(result); } finally { response.close(); } } consume()这个方法,其功能就是关闭HttpEntity是的流,
application/json 是一种常用的HTTP请求头,用于指定请求的内容类型为JSON格式
使用 application/json
编码方式,可以将数据序列化成一个 JSON 字符串作为请求主体。
public static void main(String[] args) throws Exception {
// 创建 ContentType 对象为 form 表单模式
ContentType contentType = ContentType.create("application/json", StandardCharsets.UTF_8);
String url = "http://localhost:10010/user/body";
HttpPost httpPost = new HttpPost(url);
//设置请求头,添加到 HttpPost 头中
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
//设置报文和通讯格式
String jsonParam = "{\"name\":\"John\", \"age\":30}";
StringEntity stringEntity = new StringEntity(jsonParam, StandardCharsets.UTF_8);
httpPost.setEntity(stringEntity);
//获取默认配置的 HttpClient
CloseableHttpClient httpclient = HttpClients.createDefault();
//调用 HttpClient 的 execute 方法执行请求
CloseableHttpResponse response = httpclient.execute(httpPost);
try {
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
System.out.println(result);
} finally {
response.close();
}
}
multipart/form-data
这种编码方式主要用于文件上传,可以有效地传输二进制(非字母数字)数据,同时还可以携带其他信息
最常见的 POST 提交数据的方式,也是典型的key-val键值对,无需转化,在request中直接获取,框架也会将同名属性封装到接收对象中,支持文件流上传
如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。
但是如果有type=file的话,就要用到multipart/form-data了。
4、 application/octet-stream
二进制流数据(如常见的文件下载)