Http协议简介
HTTP协议即超文本传输协议。是客户端和服务端交互时,数据的格式规范。分为HTTP请求和HTTP响应。
- 浏览器向服务器请求某个web资源时,称之为浏览器向服务器发送了一个http请求。
- 一个HTTP响应代表着服务器向浏览器回送数据。
简单来说就是:请求:客户端发送给服务端的数据;响应:服务端发送给客户端的数据。
请求和响应分为行,头,体。先有请求后有响应,没有请求就没有响应。
HttpServletRequest
概述
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
request就是将请求文本封装而成的对象,所以通过request能获得请求文本中的所有内容,请求头、请求体、请求行
一个请求的例子:
请求行、请求头、请求体
请求行
- 本次请求的基本信息
- 格式:请求方式 请求资源 协议版本
- 例如
POST /day29/demo01 HTTP/1.1
请求头
- 本次请求的附加信息
- 格式:一行一个键值对,一个键值对是一个请求头,一次请求可以有多个请求头
- 例如:
Referer:http://localhost:8080/day29/_01http.html
- 相关方法:
- String getHeader(String name) 根据头名称得到头信息值
- long getDateHeader(java.lang.String name) 获得指定头内容Date
- int getIntHeader(java.lang.String name) 获得指定头内容int
- Enumeration getHeaderNames() 得到所有头信息name
- Enumeration getHeaders(String name) 根据头名称得到相同名称头信息值
代码示例:
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()){
String key = (String)headerNames.nextElement();
String value = req.getHeader(key);
System.out.println(key+"="+value);
}
请求体
- 本次请求的正文数据,是提交的表单参数
- 格式:表单数据的提交格式 name=value&name=value&…
- 例如:
username=lisi
- 注意:只有是POST提交,必须有带name属性的表单项,这时候请求体里才有数据;否则没有请求体
- 与表单获取相关的方法:
- String getParameter(name) :根据表单中name属性的名,获取value属性的值方法
- String[] getParameterValues(String name):专为复选框取取提供的方法
- getParameterNames():得到表单提交的所有name的方法
- Map<String , String[]> getParameterMap(): 得到表单提交的所有值的方法 //做框架用,非常实用
- getInputStream: 以字节流的方式得到所有表单数据
- 与操作非表单数据相关的方法(request也是一个域对象):
- void setAttribute(String name, Object value);
- Object getAttribute(String name);
- Void removeAttribute(String name);
- 与请求转发相关的方法:
- RequestDispatcher getRequestDispatcher(String path) //得到请求转发或请求包含的协助对象
- forward(ServletRequest request, ServletResponse response) //转发的方法
- include(ServletRequest request, ServletResponse response) //请求包含
- 与编码相关的方法:
- 解决post方式编码
- request.setCharacterEncoding("UTF-8") :告诉服务器客户端什么编码,只能处理post请求方式
- 解决get方式编码
- String name = new String(name.getBytes(“iso-8859-1”),”UTF-8”);
- 解决post方式编码
补充:其他常用请求方法
- getMethod();
- getRequestURL();
- getRequestURI();
- getServerName();
- getServerPort();
- getContextPath();
- getServletPath();
- getQueryString();
- getRemoteAddr();
- getProtocol();
示例:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.统一资源标记符 /Web_Servlet/ServletTest3
String uri = req.getRequestURI();
System.out.println(uri);
//2.统一资源定位符 http://localhost:6060/Web_Servlet/ServletTest3
StringBuffer url = req.getRequestURL();
System.out.println(url);
//3.协议和版本 HTTP/1.1
String potocol = req.getProtocol();
System.out.println(potocol);
//4.协议 http
String scheme = req.getScheme();
System.out.println(scheme);
//5.主机(域名) localhost,如果你使用的是ip地址,就显示ip地址
String serverName = req.getServerName();
System.out.println(serverName);
//6.端口 6060(这是我自己修改了的端口,默认是8080)
int port = req. getServerPort();
System.out.println(port);
//7.发布到tomcat下的项目名称 /Web_Servlet
String contextPath = req.getContextPath();
System.out.println(contextPath);
//8.servlet路径 /ServletTest3
String servletPath = req.getServletPath();
System.out.println(servletPath);
//9.获取所有请求参数,即?之后所有东西。 username=faker&password=mid
String queryString = req.getQueryString();
System.out.println(queryString);
//10.远程主机的ip地址 0:0:0:0:0:0:0:1
String remoteAddr = req.getRemoteAddr();
System.out.println(remoteAddr);
}
总结几个常用的方法
-
获取请求行的数据
- 获取请求方式数据
- 语法:Request对象.getMethod():
- 方法返回对应的请求方式字符串 (常见的请求方式 get/post)
- 一般默认请求方式都是get,只有指定了post才会有post请求。
- 获取请求行中项目路径
- 语法:Request对象.getContextPath();
- 方法返回对应的项目路径字符串
- 获取客户端IP
- 语法:Request对象.getRemoteAddr();
- 方法返回访问客户的IP地址
- 获取请求方式数据
-
获取请求头的数据
- 获取指定请求头的值
- 语法:Request.getHeader(键)
- 在请求头中,数据以键值对的方式进行存储,传入键,获取值
- 获取所有请求头的值
- 语法:Request.getHeaderNames()
- 以枚举对象的形式,返回所有请求头的值.
- 获取指定请求头的值
-
获取请求体的数据
- 获取单值参数:
String value = request.getParameter(标签体的name属性)
- 获取多值参数:
String[] values = request.getParametreValues(标签体的name属性)
- 获取所有参数:
Map<String, String[]> map = request.getParameterMap()
- 获取单值参数:
获取表单数据出现乱码的问题
Get方式不会出现乱码,因为Tomcat 8版本以上的为我们解决了。
Post方式则会出现乱码问题:一切乱码原因都是因为解码和编码方式不同
- request默认采用iso-8859字符集解码,而我们的页面是utf-8字符集编码
- 解决方法:修改解码方式,语法:Request.setCharacterEncoding(“utf-8”)
- 注意:必须在接收参数之前执行
request域对象的理解
Request是域对象,由Servlet规范提供的,能够存取数据的对象,在其作用范围里可以共享数据。
不同域对象的区别:作用范围不同
域对象存取数据的方法:
- 存数据:setAttribute(String name, Object value)
- 取数据:getAttribute(String name)
- 删数据:removeAttribute(String name)
request域对象的作用范围:
- 何时创建:一次请求开始
- 何时销毁:一次请求结束
- 作用范围:一次请求期间
Request底层原理图
HttpServletResponse
概述
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。request和response对象即然代表请求和响应,那我们要获取客户机提交过来的数据,只需要找request对象就行了。要向容器输出数据,只需要找response对象就行了。
HttpServletResponse对象代表服务器的响应。这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。
先看一个图片总览来对response建立印象
Response响应数据
如上图所示,我们能很快发现response的几个关键术语,比如响应头、响应体、状态码等
在一个访问过程中我们可以看到如下图所示的响应信息:
响应行的数据表示http协议版本为HTTP/1.1,状态码为200,这个状态码的描述是OK。
关于响应状态码
响应状态码:服务器告诉客户端(浏览器)本次请求和响应的一个状态
状态码都是3位数字
- 1xx:服务器接收客户端消息,但没有接收完成,等待一段时间以后,发送1xxx状态码
- 2xx:成功,代表:200
- 3xx:重定向,代表:302(重定向)304(访问缓存)
- 4xx:客户端错误,代表404(请求路径中没有响应的资源)405(请求方式与处理方法没有对应)
- 5xx:服务端错误,代表500(服务器内部错误)
响应头中的数据
- Content-Type: text/html —— 表示数据类型
- Content-Length: 137 —— 表示数据长度
- Date: Sun, 01 Mar 2020 10:19:50 GMT —— 日期
可以对应上面的图片来查看响应头的相关信息。
Response工作流程
相关方法
- setStatus(int sc) 设置响应状态码
- setHeader(String name, String value) 设置响应头信息
- getWrite(); 字符输出流
- getOutputStream(); 字节输出流
- setCharacterEncoding(String charset) 告知服务器使用什么编码
- setContentType(String type) 告诉响应的内容类型(text/html,application/json等)
题外话1:两种setCharacterEncoding
request.setCharacterEncoding()
指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码。值得注意的是在执行setCharacterEncoding()之前,不能执行任何getParameter()。而且,该指定只对POST方法有效,对GET方法无效。
分析原因,应该是在执行第一个getParameter()的时候,Java将会按照编码分析所有的提交内容,而后续的getParameter()不再进行分析,所以setCharacterEncoding()无效。而对于GET方法提交表单是,提交的内容在URL中,一开始就已经按照编码分析提交内容,setCharacterEncoding()自然就无效。
response.setCharacterEncoding
设置HTTP 响应的编码,如果之前使用response.setContentType设置了编码格式,则使用response.setCharacterEncoding指定的编码格式覆盖之前的设置.与response.setContentType相同的是,调用此方法,必须在getWriter执行之前或者response被提交之前
request和response经常会涉及到重定向和转发,将在下一个专题中提及。