大家好,欢迎来到IT知识分享网。
Web 开发
1. Web 基础
Browser/Server模式,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务器端。浏览器只需要请求服务器,获取Web页面,并把Web页面展示给用户即可。
1.1 HTTP协议
- HTTP请求
GET / HTTP/1.1
Host: www.sina.com.cn
User-Agent: Mozilla/5.0 xxx
Accept: */*
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8
其中,第一行表示使用GET
请求获取路径为/
的资源,并使用HTTP/1.1
协议,从第二行开始,每行都是以Header: Value
形式表示的HTTP头,比较常用的HTTP Header包括:
- Host: 表示请求的主机名,因为一个服务器上可能运行着多个网站,因此,Host表示浏览器正在请求的域名;
- User-Agent: 标识客户端本身,例如Chrome浏览器的标识类似
Mozilla/5.0 ... Chrome/79
,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...) like Gecko
; - Accept:表示浏览器能接收的资源类型,如
text/*
,image/*
或者*/*
表示所有; - Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
- Accept-Encoding:表示浏览器可以支持的压缩类型,例如
gzip, deflate, br
。
- HTTP 响应
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 21932
Content-Encoding: gzip
Cache-Control: max-age=300
<html>...网页数据...
服务器响应的第一行总是版本号+空格+数字+空格+文本,数字表示响应代码,其中2xx
表示成功,3xx
表示重定向,4xx
表示客户端引发的错误,5xx
表示服务器端引发的错误。数字是给程序识别,文本则是给开发者调试使用的。常见的响应代码有:
- 200 OK:表示成功;
- 301 Moved Permanently:表示该URL已经永久重定向;
- 302 Found:表示该URL需要临时重定向;
- 304 Not Modified:表示该资源没有修改,客户端可以使用本地缓存的版本;
- 400 Bad Request:表示客户端发送了一个错误的请求,例如参数无效;
- 401 Unauthorized:表示客户端因为身份未验证而不允许访问该URL;
- 403 Forbidden:表示服务器因为权限问题拒绝了客户端的请求;
- 404 Not Found:表示客户端请求了一个不存在的资源;
- 500 Internal Server Error:表示服务器处理时内部出错,例如因为无法连接数据库;
- 503 Service Unavailable:表示服务器此刻暂时无法处理请求。
从第二行开始,服务器每一行均返回一个HTTP头。服务器经常返回的HTTP Header包括:
- Content-Type:表示该响应内容的类型,例如
text/html
,image/jpeg
; - Content-Length:表示该响应内容的长度(字节数);
- Content-Encoding:表示该响应压缩算法,例如
gzip
; - Cache-Control:指示客户端应如何缓存,例如
max-age=300
表示可以最多缓存300秒。
- HTTP 协议版本之间的差异
HTTP 1.0 一个HTTP请求并接收一个HTTP响应,然后就关闭TCP连接。
HTTP 2.0 支持浏览器同时发出多个请求,但每个请求需要唯一标识,服务器可以不按请求的顺序返回多个响应,由浏览器自己把收到的响应和请求对应起来。
HTTP 3.0 将抛弃TCP协议,改为使用无需创建连接的UDP协议,目前HTTP 3.0仍然处于实验阶段。
2. Servlet
2.1 编写简单 Servlet
一个Servlet总是继承自HttpServlet
,然后覆写doGet()
或doPost()
方法。注意到doGet()
方法传入了HttpServletRequest
和HttpServletResponse
两个对象,分别代表HTTP请求和响应。我们使用Servlet API时,并不直接与底层TCP交互,也不需要解析HTTP协议,因为HttpServletRequest
和HttpServletResponse
就已经封装好了请求和响应。以发送响应为例,我们只需要设置正确的响应类型,然后获取PrintWriter
,写入响应即可。
// WebServlet注解表示这是一个Servlet,并映射到地址/:
@WebServlet(urlPatterns = "/")
public class HelloServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 设置响应类型:
resp.setContentType("text/html");
// 获取输出流:
PrintWriter pw = resp.getWriter();
// 写入响应:
pw.write("<h1>Hello, world!</h1>");
// 最后不要忘记flush强制输出:
pw.flush();
}
}
因为我们编写的Servlet并不是直接运行,而是由Web服务器加载后创建实例运行,所以,类似Tomcat这样的Web服务器也称为Servlet容器。
在Servlet容器中运行的Servlet具有如下特点:
- 无法在代码中直接通过new创建Servlet实例,必须由Servlet容器自动创建Servlet实例;
- Servlet容器只会给每个Servlet类创建唯一实例;
- Servlet容器会使用多线程执行
doGet()
或doPost()
方法。
复习一下Java多线程的内容,我们可以得出结论:
- 在Servlet中定义的实例变量会被多个线程同时访问,要注意线程安全;
HttpServletRequest
和HttpServletResponse
实例是由Servlet容器传入的局部变量,它们只能被当前线程访问,不存在多个线程访问的问题;- 在
doGet()
或doPost()
方法中,如果使用了ThreadLocal
,但没有清理,那么它的状态很可能会影响到下次的某个请求,因为Servlet容器很可能用线程池实现线程复用。
2.2 重定向与转发
- Reirect
重定向是指当浏览器请求一个 URL 时,服务器返回一个重定向指令,告诉浏览器地址已经变了,再使用新的 URL 重新发送新请求。
@WebServlet(urlPatterns = "/hi")
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 构造重定向的路径:
String name = req.getParameter("name");
String redirectToUrl = "/hello" + (name == null ? "" : "?name=" + name);
// 发送重定向响应:
resp.sendRedirect(redirectToUrl);
}
}
- Forward
Forward是指内部转发。当一个Servlet处理请求的时候,它可以决定自己不继续处理,而是转发给另一个Servlet处理。
@WebServlet(urlPatterns = "/morning")
public class ForwardServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/hello").forward(req, resp);
}
}
3. Session And Cookie
Session 跟 Cookie 只是为了区分不同存储对象而划分,本质上它们内容是一样的。比如 Cooklie 是存储在客户端的,Session 是存储在服务端,它们的具体内容都是一样的,可以存储用户信息或者其他的标记。
- Session
基于唯一ID识别用户身份的机制称为Session
服务器识别Session的关键就是依靠一个名为JSESSIONID
的Cookie。在Servlet中第一次调用req.getSession()
时,Servlet容器自动创建一个Session ID,然后通过一个名为JSESSIONID
的Cookie发送给浏览器
注意细节:
JSESSIONID
是由Servlet容器自动创建的,目的是维护一个浏览器会话,它和我们的登录逻辑没有关系;- 登录和登出的业务逻辑是我们自己根据
HttpSession
是否存在一个"user"
的Key判断的,登出后,Session ID并不会改变; - 即使没有登录功能,仍然可以使用
HttpSession
追踪用户,例如,放入一些用户配置信息等。
- Cookie
Servlet提供的HttpSession
本质上就是通过一个名为JSESSIONID
的Cookie来跟踪用户会话的。除了这个名称外,其他名称的Cookie我们可以任意使用。
@WebServlet(urlPatterns = "/pref")
public class LanguageServlet extends HttpServlet {
private static final Set<String> LANGUAGES = Set.of("en", "zh");
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String lang = req.getParameter("lang");
if (LANGUAGES.contains(lang)) {
// 创建一个新的Cookie:
Cookie cookie = new Cookie("lang", lang);
// 该Cookie生效的路径范围:
cookie.setPath("/");
// 该Cookie有效期:
cookie.setMaxAge(8640000); // 8640000秒=100天
// 将该Cookie添加到响应:
resp.addCookie(cookie);
}
resp.sendRedirect("/");
}
}
4. Filter
为了把一些公用逻辑从各个Servlet中抽离出来,JavaEE的Servlet规范还提供了一种Filter组件,即过滤器,它的作用是,在HTTP请求到达Servlet之前,可以被一个或多个Filter预处理,类似打印日志、登录检查等逻辑,完全可以放到Filter中。
@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("EncodingFilter:doFilter");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
}
5. Listener
任何标注为@WebListener
,且实现了特定接口的类会被Web服务器自动初始化。
@WebListener
public class AppListener implements ServletContextListener {
// 在此初始化WebApp,例如打开数据库连接池等:
public void contextInitialized(ServletContextEvent sce) {
System.out.println("WebApp initialized.");
}
// 在此清理WebApp,例如关闭数据库连接池等:
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("WebApp destroyed.");
}
}
除了ServletContextListener
外,还有几种Listener:
- HttpSessionListener:监听HttpSession的创建和销毁事件;
- ServletRequestListener:监听ServletRequest请求的创建和销毁事件;
- ServletRequestAttributeListener:监听ServletRequest请求的属性变化事件(即调用
ServletRequest.setAttribute()
方法); - ServletContextAttributeListener:监听ServletContext的属性变化事件(即调用
ServletContext.setAttribute()
方法);
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/29358.html