(1)概念
- Hyper Text Transfer Protocol 超文本传输协议
- 基于TCP/IP高级协议
默认端口号80
这两种等效 http:www.baidu.com http:www.baidu.com:80
一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
- 请求一个页面,里面的图片、js/html有很多HTTP请求
- HTTP历史版本
- 1.0 每次请求建立一次链接
- 1.1 复用链接/缓存支持
(2)请求消息
-
请求行
请求头
User-Agent:浏览器版本信息,服务器可以获取浏览器类型解决兼容问题
- Accept:告诉服务器,浏览器可以解析什么类型的格式
- Connection: keep-alive 链接可以复用
- Referer:告诉服务器我从哪里来(防盗链)
请求空行
请求体(正文)
``` // 请求行:请求方式 url 请求协议/版本 GET /WebDemo_war_exploded/d1.action?a=1 HTTP/1.1
// 请求头 键值对,浏览器告诉服务器一些信息 Host: localhost:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9
// 请求空行
// 请求体 // GET方式没有请求体,参数在url中,长度有限制 // POST方式才有请求体,格式如下 a=1
- 请求方式7种
- GET
- POST
- PUT
- DELETE
<a name="qcird"></a>
### (3)HttpServletRequest
<a name="CAMCe"></a>
#### 获取请求行
- request.getQueryString():获取url中的参数
@WebServlet(“/d1”) public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(request, resp);
/**
* 请求行
*/
// http://localhost:8080/WebDemo_war_exploded/d1?a=1&b=2
// GET
String method = request.getMethod();
// /WebDemo_war_exploded 虚拟目录
String contextPath = request.getContextPath();
// /d1 Servlet路径
String servletPath = request.getServletPath();
// a=1&b=2 get方式
String queryString = request.getQueryString();
// /WebDemo_war_exploded/d1 统一资源标识符
String requestURI = request.getRequestURI();
// http://localhost:8080/WebDemo_war_exploded/d1 统一资源定位符
StringBuffer requestURL = request.getRequestURL();
// HTTP/1.1
String protocol = request.getProtocol();
// 0:0:0:0:0:0:0:1
String remoteAddr = request.getRemoteAddr();
System.out.println(method);
System.out.println(contextPath);
System.out.println(servletPath);
System.out.println(queryString);
System.out.println(requestURI);
System.out.println(requestURL);
System.out.println(protocol);
System.out.println(remoteAddr);
}
}
<a name="wSiZz"></a>
#### 获取请求头
- request.getHeaderNames();
- request.getHeader(name);
String header = request.getHeader("User-Agent");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()){
String name = headerNames.nextElement();
String value = request.getHeader(name);
System.out.println(name+": "+value);
}
<a name="aCdG1"></a>
#### 获取请求体
- 请求体中的数据封装在流里面,普通键值对参数,用字符流;图片文件使用字节流
![image.png](https://cdn.nlark.com/yuque/0/2020/png/503653/1600160073106-60ba05e9-9b26-4477-a1d8-28066b7eb62a.png#align=left&display=inline&height=280&margin=%5Bobject%20Object%5D&name=image.png&originHeight=560&originWidth=1448&size=62169&status=done&style=none&width=724)
- 请求体中的参数封装在一行中
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
BufferedReader reader = req.getReader();
String params = null;
// a=1&b=2
while ((params = reader.readLine()) != null) {
System.out.println("----"+params);
}
}
- 获取请求参数的通用方法,GET和POST中参数都能获取到
> // ?hobby=football&hobby=soccer
> String[] as = req.getParameterValues("hobby");
>
> Map<String, String[]> parameterMap = req.getParameterMap();
> Set<String> strings = parameterMap.keySet();
> for (String key : strings) {
> System._out_.println(key + "---" + parameterMap.get(key));
> }
>
> Enumeration<String> parameterNames = req.getParameterNames();
> while (parameterNames.hasMoreElements()){
> String name = parameterNames.nextElement();
> String value = req.getParameter(name);
> System.out.println(name+"---"+value);
> }
- 中文乱码的问题
> req.setCharacterEncoding("utf-8");
<a name="vSvLp"></a>
#### 请求转发
- 特点
- 转发之后,浏览器的地址栏路径没有变化
- 只能转发到当前服务器的内部资源中
- 转发只给服务器发送一次请求
@WebServlet(“/d3”) public class Servlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 转发需要注释掉这个super
// super.doGet(req, resp); System.out.println(“d3访问”); req.setAttribute(“key”,”value”); RequestDispatcher requestDispatcher = req.getRequestDispatcher(“/Servlet4”); requestDispatcher.forward(req,resp); } }
@WebServlet(“/Servlet4”) public class Servlet4 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String key = (String) request.getAttribute("key");
System.out.println(key);
System.out.println("doGet Servlet4");
}
}
- 请求转发时的共享数据
> req.setAttribute("key","value");
> String key = (String) request.getAttribute("key");
> void removeAttribute(String name);
<a name="mHKkk"></a>
#### ServletContext
- 代表整个Web应用,可以和程序的容器来通信
- 获取ServletContext,整个项目只有一个
- req.getServletContext();
- this.getServletContext();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = req.getServletContext();
ServletContext servletContext1 = this.getServletContext();
// true
boolean one = servletContext == servletContext1;
}
- 获取MIME类型
- 格式:大类型/小类型 text/html
- tomcat软件根目录下conf/web.xml里面储存所有MIME类型
> ServletContext servletContext = req.getServletContext();<br />// image/png
> String mimeType = servletContext.getMimeType("a.png");
- 域对象:共享数据
- 共享所有用户的数据
servletContext.setAttribute("name","ss");
servletContext.getAttribute("name");
servletContext.removeAttribute("name");
- 获取文件的真实路径
- out中就是最终服务器运行的文件目录
- src中的文件全部变成 WEB-INF/classes中的文件
- 工作目录web变成out中
![image.png](https://cdn.nlark.com/yuque/0/2020/png/503653/1600242011476-654dcb93-af88-4b5e-99db-19b2964ff72c.png#align=left&display=inline&height=699&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1398&originWidth=566&size=125461&status=done&style=none&width=283)
> ServletContext servletContext = req.getServletContext();<br />
> <br />
> // web目录下的文件
> // /Users/wangchun/IdeaProjects/WebDemo/out/artifacts/WebDemo_war_exploded/b.txt
> String realPath1 = servletContext.getRealPath("/b.txt");
> <br />
> // web/WEB-INF下面的文件
> // /Users/wangchun/IdeaProjects/WebDemo/out/artifacts/WebDemo_war_exploded/WEB-INF/c.txt
> String realPath2 = servletContext.getRealPath("/WEB-INF/c.txt");
> <br />
> // 获取src下面的文件
> // /Users/wangchun/IdeaProjects/WebDemo/out/artifacts/WebDemo_war_exploded/WEB-INF/classes/c.txt
> String realPath3 = servletContext.getRealPath("/WEB-INF/classes/c.txt");
<a name="BCviu"></a>
### (4)响应消息
<a name="7jgs7"></a>
#### 响应行
- 协议/版本 状态码
- 状态码:服务器告诉客户端浏览器本次请求和响应的状态
- 1xx:服务器接受客户端消息,但没有接受完成,等待一段时间后,发送1xx状态码
- 2xx:成功。200
- 3xx:
- 重定向(302)
- 访问缓存(304)
- 4xx:客户端错误
- 路径没有对应的资源(404)
- 请求方式没有对应的doXXX方法(405)
- 5xx:服务端错误
- 服务器内部异常500
> HTTP/1.1 200
<a name="E4q5A"></a>
#### 响应头
- Content-Type:响应体的数据格式和编码格式
- Content-Disposition:服务器告诉客户端以什么格式打开响应体,
- in-line:默认值,在当前页面内打开
- attachment:以附件形式形式打开响应体,文件下载
> Date: Wed, 16 Sep 2020 02:54:04 GMT
> Accept-Ranges: bytes
> ETag: W/"368-1600221847000"
> Last-Modified: Wed, 16 Sep 2020 02:04:07 GMT
> Content-Type: text/html;charset=UTF-8
> Content-Length: 368
<a name="Okbk0"></a>
#### 响应空行
<a name="Pfazr"></a>
#### 响应体
- 传输的数据
> <!DOCTYPE html>
> <html lang="en">
> <head>
> <meta charset="UTF-8">
> <title>Title</title>
> </head>
> <body>
> <form action="/WebDemo_war_exploded/loginServlet" method="post">
> 用户名:<input type="text" name="username" /> <br>
> 密码:<input type="text" name="password" /> <br>
> <input type="submit" value="登录">
>
> </form>
> </body>
> </html>
<a name="wLrqf"></a>
### (6)HttpServletResponse
<a name="ONNSX"></a>
#### 重定向
- 相关方法
> resp.setStatus(302);
> resp.setHeader("location","/WebDemo_war_exploded/servlet2");
> // 等效于
> resp.sendRedirect("/WebDemo_war_exploded/servlet2");
> // 虚拟目录动态获取
> String contextPath = req.getContextPath();
> resp.sendRedirect(contextPath+"/servlet2");
<br />
- 当访问servlet1时,会被重定向导servlet2
- 重定向不支持setAttribute传值了
@WebServlet(“/servlet1”) public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet1");
resp.setStatus(302);
resp.setHeader("location","/WebDemo_war_exploded/servlet2");
// 上述两行代码等效于
resp.sendRedirect("/WebDemo_war_exploded/servlet2");
}
}
- 转发和重定向的区别
> 地址栏:转发不变,重定向变
> 其他服务器资源:转发只能访问当前服务器下的资源,重定向可以访问其他服务器的资源
> HTTP次数:转发是1次,重定向是2次
> setAttribute:转发支持传值、重定向不支持
> 路径:转发需要添加虚拟路径,重定向需要添加虚拟路径
<a name="EXD4l"></a>
#### 相对路径和绝对路径
- 相对路径
> ./index.html:当前目录下的index.html
> ../index.html:上一个目录下的index.html
- 绝对路径
> 1、给客户端使用需要加虚拟路径,例如重定向
> 2、给服务器使用不需要加,例如转发
<a name="TJoVT"></a>
#### 响应体字符数据
- 响应体会显示对应数据
- 注意中文乱码的问题
> resp.setContentType("text/html;charset=utf-8;");
>
> PrintWriter writer = resp.getWriter();
> writer.write("nihao");
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet1");
// 告诉客户端使用该编码
resp.setHeader("Content-type","text/html;charset=utf-8;");
// 同样的方法
// resp.setContentType("text/html;charset=utf-8;");
PrintWriter writer = resp.getWriter();
writer.write("你好");
}
<a name="DJvv5"></a>
#### 响应体字节数据
- 返回一个验证码图片
int width = 100;
int height = 200;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
graphics.setColor(Color.PINK);
graphics.fillRect(0,0,width,height);
graphics.setColor(Color.BLACK);
graphics.drawRect(0,0,width-1,height-1);
graphics.drawString("A B C D",20,25);
ImageIO.write(image,"jpg",resp.getOutputStream());
```