第一节 http请求协议
浏览器访问服务器几种方式:(常用get/post)
请求方式 | 请求说明 |
---|---|
OPTIONS | 返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。 |
HEAD | 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息 |
GET | 向特定的资源发出请求(a href="servlet"标签/js location.href="servlet") |
POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改 |
PUT | 向指定资源位置上传其最新内容 |
DELETE | 请求服务器删除Request-URI所标识的资源 |
TRACE | 回显服务器收到的请求,主要用于测试或诊断 |
CONNECT | HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器 |
HTTP请求的数据详解
浏览器通过请求的协议,将数据发送给服务器.
请求协议三部分: 请求行,请求头,请求体。
请求行: 请求地址信息
请求头: 浏览器信息以请求头形式发送给服务器 : key:value (key固定)
请求体:用户数据
get请求:只有请求行和请求头 数据以请求资源地址?拼接形式传递给服务器的 没有请求体!
例如: http://192.168.21.100:8080/demo/aa?username=jack&password=1234
<!-- get请求 -->
<a href='http://localhost:8080/demo/a.html?name=lisi'>
<img src='http://localhost:8080/demo/img/a.jpg'>
<form action="a.html" method="get">
post请求,由请求行和请求头和请求体组成, 数据以请求体形式提交!
例如: http://192.168.21.100:8080/demo/aa
<!-- post请求 -->
<form action="bb" method="post">
常见请求头汇总
请求头key | 请求头value |
---|---|
referer | 浏览器通知服务器,当前请求来自何处,如果是直接访问,则不会有这个头。常用于:防盗链 |
If-modified-Since | 浏览器通知服务器,本地缓存的最后变更时间。与另一个响应头组合控制浏览器页面的缓存。 |
cookie | 与会话有关技术,用于存放浏览器缓存的cookie信息。 |
user-agent | 浏览器通知服务器,客户端浏览器与操作系统相关信息 |
connection | 保持连接状态。Keep-Alive 连接中,close 已关闭 |
host | 请求的服务器主机名 |
content-length | 请求体的长度 |
content-type | 如果是POST请求,会有这个头,默认值为application/x-www-form-urlencoded,表示请求体内容使用url编码 |
accept | 浏览器可支持的MIME类型。文件类型的一种描述方式。 |
mime格式 | 浏览器请求数据的类型,例如: text/html ,html文件 text/css,css文件 text/javascript,js文件 image/*,所有图片文件 |
accept-encoding | 浏览器通知服务器,浏览器支持的数据压缩格式。如:GZIP压缩 |
accept-language | 浏览器通知服务器,浏览器支持的语言。各国语言(国际化i18n) |
第二节 HttpServletRequest对象request学习
-
通过request的api我们可以获取浏览器发送的请求行的数据
- String getMethod() 获取请求方式的类型
- String getRequestURI() 获取请求行中的资源名部分
- StringBuffer getRequestURL() 获取客户端发出请求完整URL
说明: uri: 统一资源标识符,用来标识一个资源,资源路径。(相当于身份证) url: 统一资源定位符,是一种具体的URI,可以用来标识一个资源.并且指明了如何定位一个资源.(相当于身份证中的地址) - String getProtocol() 获取当前协议的名称和版本
- String getRemoteAddr() 获取IP地址6. int getLocalPort() 获取端口
-
请求头的组成元素(通过request获取请求头信息)
@WebServlet(name = "DemoServlet2",urlPatterns = "/demo2")
public class DemoServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
/**
* 1. String getHeader(String name)
以 String 的形式返回指定请求头的值
* */
String header = request.getHeader("User‐Agent");
System.out.println("getHeader:"+header);
System.out.println();
/**
* 2. Enumeration getHeaderNames()
返回此请求包含的所有头名称的枚举
* */
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()){
System.out.println("getHeaderNames:"+headerNames.nextElement());
}
}
}
测试结果:
getHeader:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/63.0.3239.132 Safari/537.36
getHeaderNames:host
getHeaderNames:connection
getHeaderNames:cache‐control
getHeaderNames:user‐agent
getHeaderNames:upgrade‐insecure‐requests
getHeaderNames:accept
getHeaderNames:accept‐encoding
getHeaderNames:accept‐language
getHeaderNames:cookie
-
Request接收请求数据(***)
方法名 | 描述 |
---|---|
String getParameter(String name) | getParameter获得指定参数名对应的值。如果没有返回null,如果只有多个获得第一个。 例如:username=jack |
String[] getParameterValues(name) | getParameterValues[] 获取请求数据key相同的多个数据 |
/**
* 方法封装 类封装 原子性 单一 原则
*/
@WebServlet("/requestServlet")
public class RequestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");// 获取用户提交用户名信息
String[] hobbies = request.getParameterValues("hobby");//
System.out.println("用户名 = "+username);
System.out.println("兴趣爱好:"+ Arrays.toString(hobbies));
}
}
-
Request的其他作用 (*)
String getContextPath() 获取应用程序名称
通常情况,工程名称=发布的应用程序名称。
如果应用程序名称发生改变,那么我们如何获取呢? 通过getContextPath()可以获取发布的应用程序名称。
第三节 HttpServletResponse对象response学习
状态码:服务器与浏览器用于确定状态的固定数字号码,数字用来表示服务器针对请求做出的响应的状态,常见的响应状态码:
302 Move temporarily 重定向,请求的资源临时从不同的 URI响应请求。
304 Not Modified 从缓存中读取数据,不从服务器重新获取数据
404 :请求资源不存在。通常是用户路径编写错误,也可能是服务器资源已删除。
403 Forbidden 服务器已经理解请求,但是拒绝执行它
405 Method Not Allowed 请求行中指定的请求方法不能被用于请求相应的资源
500 :服务器内部错误。通常程序抛异常。
-
响应头 (key:value形式)
响应头Key | 响应头value |
---|---|
location | 指定响应的路径,需要与状态码302配合使用,完成跳转。 |
content-Type | 响应正文的类型(MIME类型)例如:text/html;charset=UTF-8 |
content-disposition | 通过浏览器以附件形式解析正文,例如:attachment;filename=xx.zip |
set-cookie | 与会话相关技术。服务器向浏览器写入cookie |
content-encoding | 服务器使用的压缩格式,例如:gzip |
content-length | 响应正文的长度 |
refresh | 页面刷新,例如:3;url=www.itcast.cn //三秒刷新页面到www.itcast.cn |
server | 指的是服务器名称,默认值:Apache-Coyote/1.1 |
last-modified | 服务器通知浏览器,文件的最后修改时间。与If-Modified-Since一起使用。 |
Response常见方法:
addCookie(Cookie cookie):这个方法是向Response容器中添加一个Cookie,然后服务器容器会自动的将这个Cookie回写给客户机的,至于Cookie的相关知识我们会在后面的文章中进行详解,这篇文章中这个方法暂时用不到。
addDateHeader(String name ,long date):这个是向客户机添加一个时间值属性的响应头信息,比如那个缓存的响应头expires
addHeader(String name,String value):这个是向客户机添加一个字符串值属性的响应头信息,比如重定向的响应头location
addIntHeader(String name ,int value):这个是向客户机添加一个字符串属性的响应头信息
containsHeader(String name):这个方法是判断是否含有这个响应头信息字段
encodeURL(String name):这个方法是用于url改写的功能的,这个和session有关,等到说session那篇文章的时候在详细说明
sendRedirect(String name):这个方法是用于请求重定向的,和响应头中的location字段的作用相同
setHeader(String name,String value)/setIntHeader(String name,int value)/setDateHeader(String name,long date):这些方法和addHeader方法是相对应的,唯一和addHeader不同的是,addHeader是向Response中添加一个响应头信息,而setHeader是修改一个响应头信息的。
setStatus(int value):通过这个方法是设置响应码的,比如:200,304,404等。
getOutputStream():通过这个方法可以拿到一个字节流,然后可以向Response容器中写入字节数据,最后客户机向Response容器中拿去数据进行显示
getWriter():通过这个方法可以拿到一个字符流(PrintWriter),然后可以向Response容器中写入字符数据,最后客户机向Response容器中拿去数据进行显示
setContentLength():通过这个方法设置服务器向用户返回的数据长度,我们在HTTP协议详解这篇blog中的那个压缩数据的返回的例子中有说到
setContentType():方法可以直接设置响应头content-type的内容
-
转发和重定向的区别
1. 转发在一次请求中完成,重定向是两次请求
2. 转发操作发生在服务器内部,重定向是浏览器执行操作
3. 转发地址栏不变(只有一次请求,一个地址),重定向,地址栏变化(两次请求,两个地址)
4. 转发可以在一次请求中共享数据,重定向不行(重定向两次请求)
1530781134215.png
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
// 1. 只对post提交数据有效 请求体数据有效 2.必须要request.getParameter之前执行
// 1.获取用户名和密码
response.setContentType("text/html;charset=utf-8");// text/plain .txt text/xml xml text/html text/json ajax
// 获取输出流 向浏览器发送数据
PrintWriter out = response.getWriter();
String name = request.getParameter("name");
String password = request.getParameter("password");
System.out.println("用户名 = " + name);
// 2.访问数据库
String sql = "select * from users where name = ? and password = ?";
JdbcTemplate template = new JdbcTemplate(C3p0Utils.getDataSource());
User existUser = null;
try {
// 单一原则 查不到对象template报运行错误
existUser = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), name, password);
} catch (DataAccessException e) {
e.printStackTrace();
}
// 3. 查询结果 转发和重定向处理
if (existUser == null) {
// response.sendRedirect("login.html");
// 转发完成登录错误 信息提示 request绑定一个错误信息 key login_error
request.setAttribute("login_error","账号或密码错误");
// 跳转到显示登录错误信息的servlet
request.getRequestDispatcher("/loginErrorServlet").forward(request,response);
} else {
// response.setStatus(302);
// 服务器发送给浏览器状态码 302 浏览器接受302 向location地址发送新的请求
// response.setHeader("Location","index.html");
// 这行代码相当于上面两行
response.sendRedirect("index.html");
}
}
}
@WebServlet("/loginErrorServlet")
public class LoginErrorServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 登录错误显示处理
PrintWriter out = response.getWriter();
out.print("<html>");
String errorinfo = (String)request.getAttribute("login_error");
// request绑定错误信息获取
out.print("<font color='red'>"+errorinfo+"</font>");
out.print("<form action='loginServlet' method='post'>");
out.print("用户名<input type='text' name='name'><br>");
out.print("密码<input type='password' name='password'><br>");
out.print("<input type='submit' value='登录'>");
out.print("</form>");
out.print("<html>");
}
}
案例-Response对象完成下载服务器资源
-
关于工程目录结构的说明
工程目录结构.PNG
@WebServlet(name = "loadServlet", urlPatterns = "/loadServlet")
public class LoadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获取浏览器提交过来的文件名
String filename = request.getParameter("filename");
//获取服务器资源位置 : 通过ServletContext对象 一个流两个头:附件弹窗头/文件类型头
ServletContext servletContext = getServletContext();
//获取资源的绝对路径
String realPath = servletContext.getRealPath("/WEB-INF/"+filename);
//创建文件对象,如果对象存在,那么则输出
File file = new File(realPath);
if(file.exists()){
//设置响应头"下载附件弹窗"
// attachment 附件形式 inline 浏览器直接打开的资源
response.setHeader("content-disposition","attachment;filename="+filename);
// 根据文件名扩展名 获取文件对应的Mime类型 然后将文件类型告诉response
String mime = servletContext.getMimeType(filename);
response.setContentType(mime);
//创建一个response的输出流
ServletOutputStream os = response.getOutputStream();
//创建文件的输入流 内存->程序
InputStream in = new FileInputStream(file);
int len = -1;
byte[] bytes = new byte[1024*4];
while((len=in.read(bytes))!=-1){
os.write(bytes,0,len);
}
in.close();
}
}
关于下载时文件名乱码的处理
response.setHeader("Content-Disposition","attachment;filename="+new String(filename.getBytes("gbk"), "ISO8859-1"));
网友评论