文章目录
请求与响应
HTTP请求(request)
request请求包含三个部分,分别为请求行、请求头、请求体。其中请求行包含请求的方法(Get或Post)、请求地址、HTTP协议版本号;请求头中包含服务的相关信息,例如当前访问设备的系统信息(User-Agent),浏览器使用的语言(Accept-Language),请求信息的长度(Content-Length)和Cookie信息(Cookie);请求体即为请求的内容。
示例,在百度首页搜索中搜索Java,按F12查询信息
在Network标签里查看第一个请求的Request Header部分,点击view source
查看源码,可以看到第一行即为请求行,表明该请求为Get方法进行请求,请求路径为/s?ie=UTF-8&wd=Java
并且使用的HTTP传输协议为1.1版本。
从第二行开始为请求头的内容:
- User-Agent:描述了当前使用的64位Windows系统,访问的浏览器为Chrome,浏览器版本为88.0
- Accept-Language: 描述了浏览器使用的是中文(zh-CN)
- Cookie:描述了Cookie信息
在Query String Parameters中记录的是请求体,其中描述了请求的两个参数ie为UTF-8,wd为Java即搜索的条件。
通过请求实现移动端和PC端页面区别开发
针对于在请求头中的User-Agent属性能够记录当前访问的设备信息,所以可以根据User-Agent的值区分移动端和PC端进而针对不通的布局进行单独开发。
示例:
package com.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/RequestTest")
public class RequestTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求头的User-Agent属性,并在控制台打印
String userAgent = req.getHeader("User-Agent");
System.out.println(userAgent);
resp.setContentType("text/html;charset=UTF-8");
if (userAgent.contains("Windows")) {
resp.getWriter().println("<h1 style='color:red'>PC端界面</h1>");
} else if (userAgent.contains("iPhone")) {
resp.getWriter().println("<h1 style='color:green'>移动端界面</h1>");
}
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>RequestTest</title>
</head>
<body>
<form action="/requestTest/RequestTest" method="get">
<h1>登录</h1>
用户名:<input type="text" name="username"/><br>
密码:<input type="password" name="password"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
可以通过点击F12右上角的图标切换移动端和PC端
当在PC端提交表单时,可以返回第一个结果
当在移动端提交表单时,可以返回第二个结果
HTTP响应(response)
response响应同样包含三个部分即响应行、响应头、响应体。响应行记录了HTTP通信协议版本,响应状态码以及状态码对应的描述;响应体记录了本次返回的信息,例如:返回体的类型(Context-Type),响应时间(Date)等;最后是响应体即服务器返回的结果。
示例:同样是百度搜索Java
查看Response Header部分,第一行即为响应行,表明使用的HTTP协议为1.1版本且返回状态码为200即为成功;以下内容为响应头的内容:
- Content-Type:描述了返回结果按照HTML来解析响应体
- Date:描述了响应的时间
查看Response标签的内容,此项记录了服务端向浏览器最终返回的结果
常见的响应码
响应码 | 描述 |
---|---|
200 | 服务器处理成功 |
404 | 无法找到文件 |
500 | 内部服务器错误 |
403 | 服务器拒绝访问 |
301、302 | 请求重定向 |
400 | 无效请求 |
401 | 未经过授权 |
503 | 无法处理请求 |
Content-Type
Content-Type决定了用那种方式对响应体进行解析,下面列举一下几种常见的方式:
MIME类型 | 描述 |
---|---|
text/plain | 纯文本 |
text/html | HTML文档 |
text/xml | XML文档 |
application/x-msdownload | 需要下载的资源 |
image/jpeg image/gif image/… | 图片资源 |
请求转发与响应重定向
在JavaWeb的开发过程中会存在多个页面的跳转及Servlet处理,所以J2EE提供了两种跳转方式分别为请求转发与响应重定向。
请求转发
请求转发是在浏览器向服务端发送请求的同时将其转到新的请求上的过程。该过程只会产生一次请求,完全是在服务端内部进行跳转。
语法:request.getRequestDispacher(String var1).forward(HttpServletRequest req, HttpServletResponse resp)
响应重定向
重定向是在浏览器向服务端发送请求后先有第一个Servlet处理后向浏览器返回响应,通知浏览器重新发起新的请求。该过程会产生两次请求,在浏览器端进行跳转。
语法:response.sendRedirect(String var1)
请求自定义属性
在请求的过程中,请求能够创建自定义属性,可以通过HttpServletRequest的setAttribute(String var1, String var2)赋予请求属性和值和getAttribute(String var1)来获取属性值。
示例:
通过请求转发的方式访问新的Servlet,在请求的过程中为请求添加username属性,可以在IndexPage类中再次被获取。
package com.servlet.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/direct/login")
public class ReqDirect extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("username", "Tom");
// 请求转发
req.getRequestDispatcher("/direct/index").forward(req, resp);
}
}
package com.servlet.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/direct/index")
public class IndexPage extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = (String) req.getAttribute("username");
resp.getWriter().println(username + " login success!</h1>");
}
}
在浏览器中可以观察到地址还是/direct/login
但返回的响应却是IndexPage发出的,而且ReqDirect中请求的属性也能在IndexPage中被获取。
而如果使用响应重定向,修改ReqDirect类中的代码:
package com.servlet.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/direct/login")
public class ReqDirect extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("username", "Tom");
// 响应重定向
resp.sendRedirect("/direct/index");
}
}
IndexPage类中的代码不变,可以看到以下效果
浏览器的地址变为了/direct/Index
,所以可以说明响应重定向会先返回浏览器再由浏览器发起第二次请求指向新的页面,且能看出应该返回请求属性username的位置返回的是null,即第二次发起的请求中不包含username属性。
Cookie
Cookie是浏览器的本地记录,即在本地保存网页中的用户登录信息或小文本资料。同时Cookie伴随着时效性,随着浏览器的请求一起发送给服务端。
示例:
package com.servlet.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/cookie/login")
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 创建Cookie对象
Cookie cookie = new Cookie("username", "admin");
// 向浏览器返回Cookie对象
resp.addCookie(cookie);
resp.getWriter().println("<h1>login success</h1>");
}
}
先用浏览器访问/cookie/login
为浏览器添加Cookie,再访问/cookie/index
测试Cookie是否生效。
package com.servlet.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/cookie/index")
public class IndexPage extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取浏览器中的所有Cookie,返回结果保存在Cookie数组中
Cookie[] cookies = req.getCookies();
// 判断Cookie数组是否有数据
if (cookies == null) {
resp.getWriter().println("<h1>user is not login system!</h1>");
return;
}
// 循环遍历数组,寻找username的Cookie
String username = null;
for (Cookie cookie : cookies) {
// 打印浏览器的所有Cookie
System.out.println(cookie.getName() + ":" + cookie.getValue());
if (cookie.getName().equals("username")) {
username = cookie.getValue();
break;
}
}
if (username == null) {
resp.getWriter().println("<h1>user is not login system!</h1>");
} else {
resp.getWriter().println("<h1>" + username + " login system.</h1>");
}
}
}
在访问/cookie/login
时,按F12查看请求中Cookie标签,可以找到新增的Cookie属性username及其值。
再访问/cookie/index
就可以看到登录成功的界面。此时若关闭浏览器再访问/cookie/index
界面显示为用户未登录,所以Cookie也是存在时效性的。
Cookie的时效性
一般来说只在当前访问过程中有效,一旦关闭浏览器Cookie就会被清除。所以若需要一直保存Cookie中的信息可以使用setMaxAge(int expiry)
设置Cookie存在的时间,单位为秒。
可以将Login类的代码修改如下:
@WebServlet("/cookie/login")
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("username", "admin");
// Cookie保存7天
cookie.setMaxAge(7*24*60*60);
resp.addCookie(cookie);
resp.getWriter().println("<h1>login success</h1>");
}
}
Session
Session被称为用户会话。在浏览器开始发出请求时将Cookie中的SessionId发送给Tomcat,并在内存中辟出一个地址为SessionId的空间,在此空间中可以存储属性和值,并将该地址返回给浏览器保存在Cookie中。等待再次被访问时可以依靠Cookie中存放的SessionId去Tomcat内存地址中寻找其属性和值。相比于Cookie,会话是在Tomcat内部完成,所以更加安全。
示例:
创建并存储Session
package com.servlet.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/session/login")
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("用户登录中");
// 获取Session对象
HttpSession session = req.getSession();
// 获取Session的SessionId
String sessionId = session.getId();
System.out.println(sessionId);
// 设置Session会话的属性
session.setAttribute("username", "张三");
// 转发至首页
req.getRequestDispatcher("/session/index").forward(req, resp);
}
}
创建登录成功后的Servlet,并在浏览器中先访问登录页面,将SessionId加入Cookie中,再通过请求转发至主页就可以看到Session中保存的username。
package com.servlet.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/session/index")
public class IndexPage extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取Session对象
HttpSession session = req.getSession();
// 获取SessionId并输出
System.out.println(session.getId());
resp.setContentType("text/html;charset=utf-8");
// 获取Session的属性
String username = (String) session.getAttribute("username");
resp.getWriter().println("<h1>Hello " + username + "</h1>");
}
}
按F12查看Request Headers的信息,可以看到Cookie中记录这SessionId与控制台打印输出的相同。
Session在本质上也是Cookie所以也存在时效性,当关闭浏览器重新打开时,就会重新生成一个SessionId。
ServletContext(上下文对象)
ServletContext是上下文对象,对于Web应用是全局对象。在服务器加载Tomcat过程中只能创建ServletContext对象,且不像Cookie一般在服务没有停止或重启的情况下,ServletContext都不会被销毁,伴随着程序的启动到结束。
示例:
ServletContext常用来存储页面中长时间不需要改变的东西,例如页面的期限和版权
package com.servlet.servletContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/context/login")
public class ContextLogin extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = req.getServletContext();
// 设置ServletContext属性
context.setAttribute("copyright", "©1999-2021北京创新乐知网络技术有限公司");
context.setAttribute("title", "CSDN");
resp.getWriter().println("init success");
}
}
当访问/context/login
时,程序会添加全局对象。
package com.servlet.servletContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/context/indexPage")
public class ContextIndexPage extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = req.getServletContext();
String title = (String) context.getAttribute("title");
String copyright = (String) context.getAttribute("copyright");
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().println("<h1>" + title + "</h1>" + "<p>" + copyright + "</p>");
}
}
在访问/context/indexPage
时,就能看到全局变量中的属性。
Java Web作用域
对象 | 作用域 |
---|---|
HttpServletRequest (请求对象) | 当服务器完成响应后,该请求就会被销毁 |
HttpSession (用户会话对象) | 用户会话会默认保存30分钟,若30分钟内无访问的话就会被销毁 |
ServletContext (web应用全局对象) | 会一直保存在内存中,直到服务停止或重启才会被销毁 |
如果关闭浏览器用户会话是不会被销毁的,而是只会更换一个SessionId,并不会销毁Session
一般来说为了便于维护和减少资源浪费,优先使用作用域小的对象