接:HTTP协议和Web服务器的使用
一、@WebServlet(...)填写的资源路径的问题1.括号内的路径必须以“/”开头(特殊情况除外)
2.路径不能重复
3.正常情况:"/hello" "/hello/world" "/hello.html" "/hello.jpg"
4.几个特殊情况
1)通配符:"*.do":只要路径后缀名是.do的url都归我管
此时访问:lifecycle.do、a/b.do....等都可以访问到,只要是以.do结尾的都可以访问到。
2)"/":所有的url都归我管(但是精确过的如/liftcycle等的会正常走它的,不归我管,其他没有的url都归我管)
3)"":代表根url
什么情况下tomcat会启动失败:访问http://127.0.0.1:8080 是可以访问到的
1)端口被占用
2)动态资源的绑定路径有错误时
二、响应体是文本内容并且字符集编码是utf-8的场景需要做:
1.设置字符集编码
2.设置Content-type的响应头
3.写响应体
不用调用setHead("Content-type","..."),直接:
public class WriteResponse extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/plain");//可以省略";charset="utf-8",会自动补上
//先设置字符集再getWriter(),否则还会乱码
PrintWriter writer = resp.getWriter();
writer.print("1");
writer.println("12");
writer.printf("123");
}
}
三、读取请求参数(params)—读取网页中收集到的用户信息
GET方法的参数放在查询字符串query string中
POST方法的参数放在query string和request body中(ps:必须是form表单提交的POST请求【请求的Content-type必须是application/x-www-form-urlencoded类型】)
通过req.getParameters(...)系列读取(对于GET和POST,我们的代码采用相同的方式读取)
1.GET请求的读取准备send-param.html:
Title
//读取Get请求
@WebServlet("/get-param")
public class GetParam extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
}
提交后得到:http://127.0.0.1:8088/first-webapp/get-param?username=123&password=123456,验证了请求的name是放在query String中的。
当GET请求时总结:
1)请求参数放在URL的query string中,格式是name=value&name=value
2)value是中文还是英文都可以正常读取
3)如果只有name没有value,读到的是一个空的字符串""
4)如果连name都没有,读到的是null
2.POST请求的读取
//读取POST请求
@WebServlet("/post-param")
public class PostParam extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("|"+username+"|");
System.out.println("|"+password+"|");
}
}
提交后,根据Content-Length有值知道存在请求体(tomcat在解析时不知道请求体的字符集编码是什么,只能按照默认字符集编码(不是utf-8),所以中文提交后的结果有问题:
所以需要设置请求的字符集编码):
@WebServlet("/post-param")
public class PostParam extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");//设置请求的字符集编码(需要加上这步)
// req.setCharacterEncoding("utf-8");//设置响应的字符集编码(只是用来和上一步对比一下)
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("|"+username+"|");
System.out.println("|"+password+"|");
}
}
对于post请求,参数可以在form表单,也可以在查询字符串中:
POST请求时总结:1)请求参数可以放在url的query string中,也可以放在请求体request body中(前提必须是form表单提交),格式都是name=value&name=value形式
2)value是英文没问题,但是中文有问题,所以读取前应设置请求的字符集编码:req.setCharacterEncoding(...)
3)如果只有name没有value,读到的是一个空的字符串""
4)如果连name都没有,读到的是null
建议标准的读取参数代码如下:
//get和post请求的读取(:统一格式)
public class StandParam extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");//虽然对get没用,但是写上也没有副作用
String username = req.getParameter("username");
//String.trim():去除字符串两边的空格
if(username==null||username.trim().isEmpty()){
//用户没有填写正确信息,进行一定的错误处理
//比如:响应400或者重定向到其他页面
}
//正常使用username
//读取到的value一定是String类型,如果需要其他类型,比如int,需要使用Integer.parseInt(str)进行转换
//但是转换可能异常:Integer.parsetInt("hello")就会异常
//如果还有其他严格的格式要求,需要自行写代码处理
}
}
3.GET方法和POST方法的区别⭐⭐
1.根本区别:语义不同,GET代表的获取的语义,POST代表提交的语义
具体表现上的不同:
2.标准中规定:GET不应该带有请求体,POST可以带有请求体
3.有请求参数的话,GET请求放在查询字符串中,POST请求放在查询字符串或请求体(form表单)中。
由于各个浏览器的实现,url长度限制(1000个字符)短于请求体限制(无限制),所以有说法POST可以带的参数多,GET带的少,但实际上这种说法不准确,这完全是实现上的问题,标准上没有任何规定。
URL一般会记录在日志中,请求体不会记录,所以还有种说法:POST比GET稍微安全一点,但其实本质是都不安全的,如果真正要安全:使用HTTPS协议
4.将HTTP方法类比成SQL动作:GET方法可以类比成select语句【GET(select)】、POST(insert)、PUT(update)、DELETE(delete)——restful上有这样的建议
所以有:GET和PUT是幂等的,GET无副作用,PUT有副作用;POST不是幂等的;DELETE无副作用
4.1:幂等和副作用是两个约束限制等级:无副作用>幂等【无副作用一定幂等,幂等不一定没有副作用】
4.2:幂等:执行select,只要背后的数据不变,得到的结果一定不变,如select*from 表 where.name='xx';只要数据不变,永远执行下去得到的结果一定一致0,这就叫做幂等的。所以insert为什么不幂等:同一个数据/语句,第一次插入成功,但以后插入也可能插入失败。
4.3:无副作用:执行不会影响数据,叫做无副作用
现象1:GET请求直接刷新浏览器,浏览器就自动重新发送请求了(GET没有副作用),POST请求刷新浏览器有些浏览器会提示用户你确定要重新发送一次POST请求吗
现象2:HTTP请求是支持缓存的(Cache),为了提升访问速度。但是,GET请求支持缓存(因为它没有副作用),POST请求不支持缓存(因为有副作用)
四、资源重定向(redirect)当我去请求一个资源时,可以要求浏览器去请求另一个资源,类似:买书,买石头记,老板说资源已经不叫石头记了,你应该去买的书叫红楼梦,这是你应该发起一个新的请求买红楼梦,这个过程就是重定向。
重定向通过3XX做到:3XX+响应头:Location(location:定位到...)
1.重定向分类1)永久重定向:301 Moved Permanently
2)临时重定向:
注意:临时重定向时,关于重定向的时候是否保留原方法,历史上是没有考虑到这一点的,临时重定向时没有考虑方法保留问题,所以实现的时候,保留也行不保留也行,但大部分浏览器都实现成不保留的了(退化成GET请求)。1.1的规定中,就分成了:保留方法的临时重定向+不保留方法的临时重定向。
综述,临时重定向有三个状态码:1个历史2.保留的3.不保留的
| 302 | Found | 历史【302约等于303】 |
| 303 | See Other | 退化成GET |
| 307 | Temporary Redirection | 保留原方法的(POST重定向后方法还是POST) |
通过代码观察现象:
@WebServlet("/redirect-303")
public class Redirect303 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
redirect(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
redirect(req,resp);
}
private void redirect(HttpServletRequest req,HttpServletResponse resp){
resp.setStatus(303);
resp.setHeader("Location","/target");//由于没有实现,结果会404
}
}
关于303,是GET请求时:
发了GET请求出去,GET请求发的是/direct-303,提交后收到的响应状态码是303,响应头种有Location:/target,浏览器自动就发起了/target请求,它的请求也还是GET。
请求开始是POST时:
请求变为GET请求,说明POST请求退化了
307时的POST请求:(把resp.setStatus(303)中303改为307,其他不变进行观察)
POST请求还是POST请求,说明保留了原POST方法



