HTTP协议特点
1 HTTP协议特点 1)客户端->服务端(请求request)有三部份 a)请求行--请求行用于描述客户端的请求方式、请求的资源名称,以及使用的HTTP协议版本号
- 请求行中的GET称之为请求方式,请求方式有:POST、GET、HEAD、OPTIONS、DELETE、TRACE、PUT
常用的有:POST、GET
- 不管POST或GET,都用于向服务器请求某个WEB资源,这两种方式的区别主要表现在数据传递上,客户端通过这两种方式都可以带一些数据给服务器:
•如请求方式为GET方式,则可以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔,例如:
GET /mail/1.html?name=abc&password=xyz HTTP/1.1
GET方式的特点:在URL地址后附带的参数是有限制的,其数据容量不能超过1K。
- 如请求方式为POST方式,则可以在请求的实体内容中向服务器发送数据,例如:
POST /servlet/ParamsServlet HTTP/1.1
Host:
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
name=abc&password=xyz
- Post方式的特点:传送的数据量无限制,文件下载
b)请求头(多个)--消息头用于描述客户端请求哪台主机,以及客户端的一些环境信息等
c)请求的内容,如果没有,就是空白字符 2)服务端->客户端(响应response)有三部份 a)响应行 状态行用于描述服务器对请求的处理结果。 b)响应头 消息头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据 c)响应的内容,如果没有,就是空白字符 代表服务器向客户端回送的数据
*2 HTTP请求头和响应头含义 1)请求(客户端->服务端[request]) GET(请求的方式) /books/java.html(请求的目标资源) HTTP/1.1(请求采用的协议和版本号) Accept: */*(客户端能接收的资源类型) Accept-Language: en-us(客户端接收的语言类型) Connection: Keep-Alive(维护客户端和服务端的连接关系) Host: localhost:8080(连接的目标主机和端口号) Referer: http://localhost/links.asp(从来于哪里) User-Agent: Mozilla/4.0(客户端版本号的名字) Accept-Encoding: gzip, deflate(客户端能接收的压缩数据的类型) If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(缓存时间) Cookie(客户端暂存服务端的信息) Date: Tue, 11 Jul 2000 18:23:51 GMT(客户端请求服务端的时间) 2)响应(服务端->客户端[response]) HTTP/1.1(响应采用的协议和版本号) 200(状态码) OK(描述信息) 302(客户端请求服务端,但服务端没有对应的资源,服务端要客户端再次请求找其它的服务端,即客户端二次请求,重定向) 307(客户端请求服务端,但服务端没有对应的资源,服务端自行再次请求找其它的服务端,即客户端一次请求,转发) 304(客户端请求服务端,此时客户端缓存中有,无需再从服务端下载新的内容,服务端叫客户端自行找缓存,优化) 500 (客户端请求的资源,服务端存在,但在执行时出错) Location: http://www.baidu.com(服务端需要客户端访问的页面路径) Server:apache tomcat(服务端的Web服务端名) Content-Encoding: gzip(服务端能够发送压缩编码类型) Content-Length: 80(服务端发送的压缩数据的长度) Content-Language: zh-cn(服务端发送的语言类型) Content-Type: text/html; charset=GB2312(服务端发送的类型及采用的编码方式) Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务端对该资源最后修改的时间) Refresh: 1;url=http://www.it315.org(服务端要求客户端1秒钟后,刷新,然后访问指定的页面路径) Content-Disposition: attachment; filename=aaa.zip(服务端要求客户端以下载文件的方式打开该文件) Transfer-Encoding: chunked(分块传递数据到客户端) Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务端发送到客户端的暂存数据) Expires: -1//3种(服务端禁止客户端缓存页面数据) Cache-Control: no-cache(服务端禁止客户端缓存页面数据) Pragma: no-cache(服务端禁止客户端缓存页面数据) Connection: close(1.0)/(1.1)Keep-Alive(维护客户端和服务端的连接关系) Date: Tue, 11 Jul 2000 18:23:51 GMT(服务端响应客户端的时间)
package cn.itcast.web.http; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //重定向302+location响应头(服务端->客户端) public class Demo1 extends HttpServlet { public void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //服务端通知客户端重定向 response.setStatus(302); //服务端通知客户端重定向的目标资源 response.setHeader("location","/day05/index.html"); } }
package cn.itcast.web.http; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Demo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; System.out.println("压缩前" + data.length()); //以下代码完成将String类型压缩到byte[]中 ByteArrayOutputStream bout = new ByteArrayOutputStream(); GZIPOutputStream gout = new GZIPOutputStream(bout); gout.write(data.getBytes()); gout.flush(); gout.close(); //取出压缩后的数据 byte[] buf = bout.toByteArray(); System.out.println("压缩后" + buf.length); //将压缩后的数据输出到浏览器 response.setHeader("content-encoding","gzip"); response.setHeader("content-length",buf.length+""); //服务端以字节方式输出 response.getOutputStream().write(buf); } }
package cn.itcast.web.http; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Demo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { //通知浏览器打开一副图片 response.setHeader("content-type","image/jpeg"); InputStream is = new FileInputStream(new File("d:\\d1.jpg")); OutputStream os = response.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while( (len=is.read(buf))>0 ){ os.write(buf,0,len); } is.close(); os.close(); } }
package cn.itcast.web.http; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Demo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { //服务端通知浏览器以下载的方式打开图片 response.setHeader("content-disposition","attachment;filename=d1.jpg"); InputStream is = new FileInputStream(new File("d:\\d1.jpg")); OutputStream os = response.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while( (len=is.read(buf))>0 ){ os.write(buf,0,len); } is.close(); os.close(); } }
package cn.itcast.web.http; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Demo5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { //服务端通知浏览器3秒后转到目标页面 response.setHeader("refresh","3;url=/day05/index.html"); } }
package cn.itcast.web.http; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Demo6 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { //服务端控制各种浏览器禁止缓存页面资源 response.setHeader("expires","-1"); response.setHeader("cache-control","no-cache"); response.setHeader("pragma","no-cache"); //服务端向浏览器输出内容 response.getWriter().write("haha"); } }
3)总结 想让浏览器有何种行为,服务端只能通过响应头的方式来设置 想让服务器知道何种行为,浏览器只能通过请求头的方式来设置
2)常用的提交方式 a)GET 特点:
请求参数无论多少,都会根着URL后传递到服务端,以明文方式传递 GET方式传递有大小限制 GET方式传递信息不安全
b)POST 特点: 请求参数无论多少,都不会根着URL后传递到服务端,而是以参数形式在请求体中传递到服务端 POST方式传递无大小限制 POST方式传递信息相对安全 *3 Servlet入门 1)Servlet是SUN公司基于Java技术的一个开发动态资源支持的规范,以接口的形式出现,最终的实现类与服务器有关 2)Servlet是一种特殊的Java类,运行时服务端/容器中,接收每一个客户端的请求并响应,尊循HTTP协议 3)Servlet手工开发过程,参见<<手工创建Servlet的全过程.txt>>
package cn.itcast.web.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; //实现Servlet接口来开发Servlet程序 public class Demo11 implements Servlet { public void destroy() { } public ServletConfig getServletConfig() { return null; } public String getServletInfo() { return null; } public void init(ServletConfig arg0) throws ServletException { } public void service( ServletRequest request, ServletResponse response) throws ServletException, IOException { //取得服务端向浏览器的输出流对象 PrintWriter pw = response.getWriter(); pw.write("welcome to java web course!"); } }
*4 开发Servlet 1)类 实现 Servlet接口 + 在web.xml中配置 <servlet> <servlet-name>Demo11[servlet名字,可以任意]</servlet-name> <servlet-class>cn.itcast.web.servlet.Demo11[servlet全路径]</servlet-class> </servlet> <servlet-mapping> <servlet-name>Demo11[servlet名字,必须和上述一致]</servlet-name> <url-pattern>/qq[以/开头,提供外界用户访问的路径]</url-pattern> </servlet-mapping> 2) 类 扩展 GenericServlet + 在web.xml中配置 如果需要输出中文,需要在Servlet中如下设置: //服务端通知浏览器以指定的编码方式来显示中文 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("欢迎学习JavaServlet程序");
package cn.itcast.web.servlet; import java.io.IOException; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; //扩展GenericServlet实现Servlet程序 public class Demo12 extends GenericServlet { public void service( ServletRequest request, ServletResponse response) throws ServletException, IOException { //服务端通知浏览器以指定的编码方式来显示中文 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("欢迎学习JavaServlet程序"); } }
3) 类 扩展 HttpServlet + 在web.xml中配置 HttpServlet已经覆写service()方法,程序员无需再次覆写,只需覆写doXxxx()方法
package cn.itcast.web.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //扩展 HttpServlet实现Servlet程序 public class Demo13 extends HttpServlet { //如果浏览器是以get方式提交,则覆写doGet()方法 public void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); pw.write("<ol>"); pw.write("<li>JavaServlet</li>"); pw.write("<li>JavaJsp</li>"); pw.write("<li>JavaStruts</li>"); pw.write("</ol>"); } }
5 Servlet工作原理和生命周期 1)当浏览器第一次访问Servlet时,服务器会根据浏览器访问的路径,例如/Demo2,在web.xml文件中找到该Servlet的全路径, 进行反射。 2)调用init()为Servlet作初始化工作 3)调用doXxxxx()为浏览器响应 4)如果浏览器再次访问相同的Servlet,直实现从服务端维护的Servlet实例集合中取得对应的实现,为浏览器响应 5)同一个Servlet实例,在服务端只有一个 6)服务器在决定销毁Servlet实例之前,调用destory()方法,每个Servlet实例只会调用一次,在重新部署情况下
*6 Servlet细节 1)浏览器访问的url-pattern只是一个符合格式的任意字符串,以/开头 2)一个Servlet的url-pattern可以是1个或多个,有二种形式; a)*.xx b)/xx/* 注意:/*不能一起直接使用 3)/*和*.do的映射关系,*.do最后 4)程序员编写的Servlet其实是由tomcat容器中的Servlet引擎来处理的,引擎会产生对应的HttpServletRequest和 HttpServletResponse对应传入到Servlet的doXxxx()方法中 5)通过在web.xml文件中配置代码,让Servlet在部署时就创建 <servlet> <servlet-name>Demo21</servlet-name> <servlet-class>cn.itcast.web.servlet.Demo21</servlet-class> <load-on-startup>1</load-on-startup> </servlet> 数字小的先加载,数据大的后加载,最小为0,如果为负数和没有设置一样,需要在浏览器第一次访问时创建 6)url-pattern为/的servlet是一个缺省的servlet,用于处理当前web应用下,访问路径错误的请求 任何web服务端都有一个缺省的servlet来处理 7)每个线程会共享同一个Servlet的实例变量,所以要对敏感数据加锁 产生线程安全条件如下: a)单例 && b)实例变量 && c)实例变量进行修改操作 通过加锁的方式,对敏感数据块进行代码同步(正道) 如果你实现SingleThreadModel来解决线程安全有二个不足之处: a)SingleThreadModel接口的值与web服务器最多接收的线程数有关,可能会出现大值变小值的情况 b)SingleThreadModel接口如果发现某个线程正在占用该Servlet实例,会自动创建一个新的Servlet实例为浏览器服务, 这就违背了Servlet单例的原则
7 ServletConfig对象 1)想让当前Servlet读取一些在web.xml文件配置的初始化参数,可以使用ServletConfig对象,它是Servlet运行时的配置对象 2)init(ServletConfig)方法由Web容器调用,调用时,会传入与容器相关的ServletConfig接口的实现