Servlet(HttpServletRequest请求对象)
HTTP协议:
什么是HTTP,Http是超文本传输协议,从浏览器到服务器称为请求,从服务器回到浏览器称之为响应
URL的组成部分
协议
协议确定如何传输请求,我们主要使用http与https,常见的还有ftp与file 主机名
主机名标识服务器。运行在本地计算机(localhost)和本地网络的服务器可以简单地表示,比如用一个单词,或一个数字 IP 地址。在 Internet 环境下,主机名通常以一个顶级域名(TLD)结尾,比如 .com 或 .net。另外,也许还会有子域名作为主机名的前缀。子域名可以是任何形式的,其中 www 最为常见。子域名通常是可选的。 端口
每一台服务器都有一系列端口号。一些端口号比较“特殊”,如 80 和 443 端口。如果省略端口值,那么默认 80 端口负责 HTTP 传输,443 端口负责 HTTPS 传输。如果不使用 80 和 443 端口,就需要一个大于 1023 1 的端口号。通常使用容易记忆的端口号,如3000、8080 或 8088。 路径
URL 中影响应用程序的第一个组成部分通常是路径(在考虑协议、主机名和端口的基础上做决定很合理,但是不够好)。路径是应用中的页面或其他资源的唯一标识。 查询字符串
查询字符串是一种键值对集合,是可选的。它以问号(?)开头,键值对则以与号(&)分隔开。所有的名称和值都必须是 URL 编码的。对此,JavaScript 提供了一个嵌入式的函数 encodeURIComponent 来处理。例如,空格被加号(+)替换。其他特殊字符被数字型字符替换。 信息片断
该信息不会发送到服务端,一般只涉及到前段设置锚点,用于页面的跳转
http请求方法
HTTP 协议确定了客户端与服务器通信的请求方法集合(通常称为 HTTP verbs)。很显然,GET 和 POST 最为常见。在浏览器中键入一个 URL(或点击一个链接),服务器会接收到一个 HTTP GET 请求,其中的重要信息是 URL 路径和查询字符串。至于如何响应,则需要应用程序结合方法、路径和查询字符串来决定。 对于一个网站来说,大部分页面都响应 GET 请求。 POST 请求通常用来提交信息到服务器后台(例如表单处理)。服务器将请求中包含的所有信息(例如表单)处理完成之后,用以响应的 HTML 通常与相应的 GET 请求是一样的。与服务器通信时,浏览器只使用 GET 和POST 方法(如果没有使用 AJAX)
请求报头
我们浏览网页时,发送到服务器的并不只是 URL。当你访问一个网站时,浏览器会发送很多“隐形”信息。服务器会因此得知优先响应哪种语言的页面(例如,在西班牙下载 Chrome 浏览器,如果有西班牙语的版本,就会接收到一个西班牙语的访问页面)。它也会发送“用户代理”信息(浏览器、操作系统和硬件设备)和其他一些信息。所有能够确保你了解请求对象头文件属性的信息都将会作为请求报头发送。
请求体
除请求报头外,请求还有一个主体(就像作为实际内容返回的响应主体一样)。一般 GET请求没有主体内容,但 POST 请求是有的。 POST 请求体最常见的媒体类型是 application/x-www-form-urlendcoded ,是键值对集合的简单编码,用 & 分隔(基本上和查询字符串的格式一样)。如果 POST 请求需要支持文件上传,则媒体类型是 multipart/form-data ,它是一种更为复杂的格式。最后是 AJAX 请求,它可以使application/json
请求与响应对象综述
HttpServletRequest request 请求对象
HttpServletResponse response 响应对象
请求对象与响应对象 由服务器创建 管理 销毁 我们只是使用
当响应完成之后 服务器就会销毁这次的请求对象与响应对象
继承体系结构:
ServletRequest(接口)<--------继承<-------HttpServletRequest(接口)<------
--实现 org.apache.catalina.connector.RequestFacade@6049a827
ServletResponse(接口)<---------继承--- HttpServletResponse(接口)<------
-------实现------org.apache.catalina.connector.ResponseFacade@3bec9d4
原理
当浏览器去请求服务器的资源时 服务器收到请求后 就会创建请求对象的响应对象 请求对象将我们的请求数据封装 服务器会把请求对象和响应对象 喜欢递给service()方法 从请求对象中 去除请求的数据来用 给浏览器响应数据时 将响应的数据 放到响应对象中 当服务器真正响应浏览器时 就从响应对象中 取出数据响应给浏览器
当响应完成之后 服务器就会销毁这次的请求对象与响应对象
配置欢迎页
<welcome-file-list>
<welcome-file>hh.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
HttpServletRequest请求对象
请求对象:由服务器创建 管理 销毁
请求对象:请求行 请求头 请求体
概念
请求对象(通常传递到回调方法,这意味着你可以随意命名,通常命名为 req 或 request )它的生命周期始于 Node 的一个核心对象 http.IncomingMessage 的实例。Express 添加了一些附加功能。我们来看看请求对象中最有用的属性和方法(除了来自 Node 的req.headers 和req.url ,所有这些方法都由 Express 添加)
请求行包括:传输方式(get或post) 请求的地址(url) 协议的版本
请求头中只有:只有键值对形式存在的参数
请求实体:post传参方式,需要注意的是,当传输方式为get时,表单中的值是在地址的问号后面,
当传输方式为post时值是在请求实体中
HttpServletRequest的本质上就是HTTP协议的请求所封装的
请求对象中的方法:
1.获取请求行中的内容
Request.getMethod() 获取请求方式
Request.getRequestURI() 获取地址栏中?之前端口之后
Request.getRequestURL() 获取?之前所有,返回StringBuffer
Request.getScheme() 获取协议
Request.getContextPath() 获取根目录
Request.getQueryString() 获取?之后
2.获取请求头中的内容:
Request.getHeader(键) 键是不区分大小写的
3.获取网络信息:
request.getRemoteAddr() 获取客户端ip地址
Request.getRemotePort() 获取客户端的端口
Request.getLocalAddr() 获取服务器IP地址
Request.getLocalPort() 获取服务器端口号
4.获取表单参数:
首先获取单键单值:
Request.getParameter(键) 返回String,需要注意的是如果没有键返回的是null,有键而没有值返回空字符串;
获取同键不同值(主要针对复选框):
request.getParameterValues(键) 返回一个String[]
获取所有键的集合:
Request.getParameterNames() 返回的是Enumeration,也就是一个容器
While(enum对象.hasMoreElements()){
enum对象.nextElement();
}
- req.params
- 一个数组,包含命名过的路由参数。
- req.param(name)
- 返回命名的路由参数,或者 GET 请求或 POST 请求参数。建议你忽略此方法。
- req.query
- 一个对象,包含以键值对存放的查询字符串参数(通常称为 GET 请求参数)。
- req.body
- 一个对象,包含 POST 请求参数。这样命名是因为 POST 请求参数在 REQUEST 正文中传递,而不像查询字符串在 URL 中传递。要使 req.body 可用,需要中间件能够解析请求正文内容类型
- req.route
- 关于当前匹配路由的信息。主要用于路由调试。
- req.cookies/req.singnedCookies
- 一个对象,包含从客户端传递过来的 cookies 值。
- req.headers
- 从客户端接收到的请求报头。
- req.accepts([types])
- 一个简便的方法,用来确定客户端是否接受一个或一组指定的类型(可选类型可以是单个的 MIME 类型,如 application/json 、一个逗号分隔集合或是一个数组)。写公共API 的人对该方法很感兴趣。假定浏览器默认始终接受 HTML。
- req.ip
- 客户端的 IP 地址。
- req.path
- 请求路径(不包含协议、主机、端口或查询字符串)。
- req.host
- 一个简便的方法,用来返回客户端所报告的主机名。这些信息可以伪造,所以不应该用于安全目的。
- req.xhr
- 一个简便属性,如果请求由 Ajax 发起将会返回 true 。
- req.protocol
- 用于标识请求的协议( http 或 https )。
- req.secure
- 一个简便属性,如果连接是安全的,将返回 true 。等同于req.protocol==='https' 。
- req.url/req.originalUrl
- 有点用词不当,这些属性返回了路径和查询字符串(它们不包含协议、主机或端口)。req.url 若是出于内部路由目的,则可以重写,但是 req.orginalUrl 旨在保留原始请求和查询字符串。
- req.acceptedLanguages
- 一个简便方法,用来返回客户端首选的一组(人类的)语言。这些信息是从请求报头中解析而来的
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取请求方式
System.out.println("请求方式:" + request.getMethod());
//获取协议
System.out.println("协议:" + request.getProtocol());
//获取地址栏中?之前端口之后
System.out.println("地址栏中?之前端口之后:" + request.getRequestURI());
//获取?之前所有,返回StringBuffer
System.out.println("?之前所有,返回StringBuffer:" + request.getRequestURL());
//获取协议
System.out.println("协议:" + request.getScheme());
//获取根目录
System.out.println("根目录:" + request.getContextPath());
//获取?之后
System.out.println("?之后:" + request.getQueryString());
//3.获取网络信息:
// 获取客户端ip地址
System.out.println("客户端ip地址:" + request.getRemoteAddr());
//获取客户端的端口
System.out.println("客户端的端口:" + request.getRemotePort());
//获取服务器IP地址
System.out.println("服务器IP地址:" + request.getLocalAddr());
//获取服务器端口号
System.out.println("服务器端口号:" + request.getLocalPort());
}
运行结果:
请求方式:GET
协议:HTTP/1.1
地址栏中?之前端口之后:/Request_war_exploded/fang
?之前所有,返回StringBuffer:http://localhost:8080/Request_war_exploded/fang
协议:http
根目录:/Request_war_exploded
?之后:null
客户端ip地址:0:0:0:0:0:0:0:1
客户端的端口:57978
服务器IP地址:0:0:0:0:0:0:0:1
服务器端口号:8080
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//post请求 获取请求参数用request.getReader()
BufferedReader reader = request.getReader();
String s = reader.readLine();
System.out.println(s);
}
运行结果:
username=ffff&password=123456789&yan1=1234
username=%E5%BC%8E%E5%B1%B2&password=123456&yan1=1234
获取参数数据
Tomcat8.0 以上 Get请求中文不会乱码 Post请求会乱码
自己实现方法
@WebServlet(name = "ServletTongYong", value = "/old")
public class ServletTongYong extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
getParmater(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
private void getParmater(HttpServletRequest request, HttpServletResponse response) {
String s = null;
if (request.getMethod().equals("GET")) {
s = request.getQueryString();
} else if (request.getMethod().equals("POST")) {
try {
s = request.getReader().readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
String[] split = s.split("&");
String[] split1 = split[0].split("=");
System.out.println(split1[0]);
System.out.println(split1[1]);
String[] split2 = split[1].split("=");
System.out.println(split2[0]);
System.out.println(split2[1]);
String[] split3 = split[2].split("=");
System.out.println(split3[0]);
System.out.println(split3[1]);
}
}
运行结果:
username
san
password
123456
yan1
123123
request中的方法
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String yan1 = request.getParameter("yan1");
System.out.println(username);
System.out.println(password);
System.out.println(yan1);
}
运行结果:
????±?
123456
8888
浏览器URL解码问题
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String queryString = request.getQueryString();
//编码
//URLEncoder.encode(queryString, "UTF-8");
//解码
String decode = URLDecoder.decode(queryString, "UTF-8");
System.out.println(queryString);
System.out.println(decode);
}
运行结果:
name=xxx%20password=123456
name=xxx password=123456
name=%E5%BC%8E%E5%B1%B2password=123456
name=弎屲password=123456
name=amiyapassword=123456
name=amiyapassword=123456
GET请求方式 form表单的参数会将action添加的参数全部覆盖问题
需要注意的是当用到form表单时,form表单的action后面如果跟了自己添加的参数,如果请求方式是get,表单的参数会将action添加的参数全部覆盖掉。
解决方式:
1)把get换成post
2)使用get的话,可以用隐藏域