(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 {
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {super.doGet(request, resp);/*** 请求行*/// http://localhost:8080/WebDemo_war_exploded/d1?a=1&b=2// GETString 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.1String protocol = request.getProtocol();// 0:0:0:0:0:0:0:1String 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>#### 获取请求体- 请求体中的数据封装在流里面,普通键值对参数,用字符流;图片文件使用字节流- 请求体中的参数封装在一行中
@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);BufferedReader reader = req.getReader();String params = null;// a=1&b=2while ((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 {
@Overrideprotected 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();
@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext servletContext = req.getServletContext();ServletContext servletContext1 = this.getServletContext();// trueboolean 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中> 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 {
@Overrideprotected 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");
@Overrideprotected 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());
```
