HTTP协议
本文是基于Windows 10系统环境,学习和使用HTTP协议:
Windows 10MyEclipse 10
一、 HTTP协议的基本概念
(1) HTTP协议的定义
对浏览器客户端和服务器端之间数据传输的格式规范
(2) request的内容
request请求(浏览器->服务器)
GET
/day09
/hello HTTP
/1.1
Accept
: text
/html
,image
/*
Accept
-Charset
: ISO
-8859-1
Accept
-Encoding
: gzip
,compress
Accept
-Language
: en
-us
,zh
-
Host
: www
.it315
.org
:80
If
-Modified
-Since
: Tue
, 11 Jul
2000 18:23:51 GMT
Referer
: http
://www
.it315
.org
/index
.jsp
User
-Agent
: Mozilla
/4.0 (compatible
; MSIE
5.5; Windows NT
5.0)
Cookie
:name
=eric
Connection
: close
/Keep
-Alive
Date
: Tue
, 11 Jul
2000 18:23:51 GMT
name
=eric
&password
=123456
request请求相关API代码
request
.getMethod();
request
.getRequetURI()
request
.getRequetURL()
request
.getProtocol()
request
.getHeader("名称")
request
.getHeaderNames()
Enumeration
<String> enums
= request
.getHeaderNames();
while(enums
.hasMoreElements()){
String headerName
= enums
.nextElement();
String headerValue
= request
.getHeader(headerName
);
}
request
.getInputStream()
InputStream in
= request
.getInputStream();
byte[] buf
= new byte[1024];
int len
= 0;
while((len
=in
.read(buf
))!=-1){
String str
= new String(buf
, 0, len
);
System
.out
.println(str
);
}
request获取GET与POST提交的参数
request
.getParameter("参数名");
request
.getParameterValues("参数名");
Enumeration
<String> enums
= request
.getParameterNames();
while(enums
.hasMoreElements()){
String paraName
= enums
.nextElement();
String paraValue
= request
.getParameter(paraName
);
System
.out
.println(paraName
+"="+paraValue
);
}
请求参数编码问题
request
.setCharacterEncoding("utf-8");
String name
= new String(name
.getBytes("ISO-8859-1"),"utf-8");
(2) response的内容
response响应(服务器->浏览器)
HTTP
/1.1 200 OK
Location
: http
://www
.it315
.org
/index
.jsp
Server
:apache tomcat
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
Content
-Disposition
: attachment
; filename
=aaa
.zip
Transfer
-Encoding
: chunked
Set
-Cookie
:SS
=Q0
=5Lb_nQ
; path
=/search
Expires
: -1
Cache
-Control
: no
-cache
Pragma
: no
-cache
Connection
: close
/Keep
-Alive
this
is hello servlet!!!
response请求相关API代码
response
.setStatus(404)
response
.setHeader("name","value")
response
.setHeader("Server","JBoss")
response
.getWriter().writer("hello");
response
.getOutputStream().writer("hello".getBytes());
响应参数编码问题
response
.setCharacterEncoding("utf-8");
(3) 案例
重定向
response
.setStatus(302)
response
.setHeader("location","/day09/adv.html")
response
.sendRedirect("/day09/adv.html")
隔3秒后,跳转至新页面
response
.setHeader("refresh","3;/day09/adv.html")
发送图片
response
.setContentType("image/jpg"); /tomcat
/conf
/web
.xml
FileInputStream in
= new FileInputStream(new File("e:/mm.jpg"));
byte[] buf
= new byte[1024];
int len
= 0;
while(len(in
.read(buf
))!=-1){
response
.getOutputStream().write(buf
,0,len
);
}
二、 Servlet编程
(1) Servlet映射问题
web.xml配置文件
<servlet-mapping>
<servlet-name>FirstServlet
</servlet-name>
<url-pattern>/first
</url-pattern>
</servlet-mapping>
精确匹配
url-pattern 浏览器输入
/first http://localhost:8080/day10/first
/itcast/demo1 http://localhost:8080/day10/itcast/demo1
模糊匹配
url-pattern 浏览器输入
/* http://localhost:8080/day10/任意路径
/itcast/* http://localhost:8080/day10/itcast/任意路径
*.后缀名 http://localhost:8080/day10/任意路径.后缀名
*.do http://localhost:8080/day10/任意路径.do
*.action http://localhost:8080/day10/任意路径.action
*.html(伪静态) http://localhost:8080/day10/任意路径.html
注意事项
1. url-pattern要么以 / 开头,要么以*开头。 例如, itcast是非法路径。
2. 不能同时使用两种模糊匹配,例如 /itcast/*.do是非法路径
3. 当有输入的URL有多个servlet同时被匹配的情况下:
3.1 精确匹配优先。(长的最像优先被匹配)
3.2 以后缀名结尾的模糊url-pattern优先级最低!!!
(2) Servlet的自动加载
默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。 改变servlet创建对象的时机: 提前到加载web应用的时候!!! 在servlet的配置信息中,加上一个即可!!
web.xml配置文件
<servlet>
<servlet-name>LifeDemo
</servlet-name>
<servlet-class>gz.itcast.c_life.LifeDemo
</servlet-class>
<load-on-startup>1
</load-on-startup>
</servlet>
(3) Servlet的多线程并发问题
servlet对象在tomcat服务器是单实例多线程的 因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。解决方案 1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步) 2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。
(4) ServletConfig对象
作用 ServletConfig对象: 主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)对象创建和得到 创建时机: 在创建完servlet对象之后,在调用init方法之前创建。 得到对象: 直接从有参数的init方法中得到!!!核心API
String
getInitParameter(String name
)
Enumeration
getInitParameterNames()
ServletContext
getServletContext()
String
getServletName()
servlet的初始化参数配置web.xml
<servlet>
<servlet-name>ConfigDemo
</servlet-name>
<servlet-class>gz.itcast.f_config.ConfigDemo
</servlet-class>
<init-param>
<param-name>path
</param-name>
<param-value>e:/b.txt
</param-value>
</init-param>
<init-param>
<param-name>path2
</param-name>
<param-value>e:/a.txt
</param-value>
</init-param>
</servlet>
public class ConfigDemo extends HttpServlet {
public void doGet(HttpServletRequest request
, HttpServletResponse response
)
throws ServletException
, IOException
{
String path
= this.getServletConfig().getInitParameter("path");
File file
= new File(path
);
BufferedReader br
= new BufferedReader(new FileReader(file
));
String str
= null
;
while( (str
=br
.readLine())!=null
){
System
.out
.println(str
);
}
Enumeration
<String> enums
= this.getServletConfig().getInitParameterNames();
while(enums
.hasMoreElements()){
String paramName
= enums
.nextElement();
String paramValue
= this.getServletConfig().getInitParameter(paramName
);
System
.out
.println(paramName
+"="+paramValue
);
}
String servletName
= this.getServletConfig().getServletName();
System
.out
.println(servletName
);
}
}
(5) ServletContext对象
基本概念 ServletContext对象 ,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一个ServletContext对象。核心API
String
getContextPath()
String
getInitParameter(String name
)
Enumeration
getInitParameterNames()
void setAttribute(String name
, Object object
)
Object
getAttribute(String name
)
void removeAttribute(String name
)
RequestDispatcher
getRequestDispatcher(String path
)
String
getRealPath(String path
)
InputStream
getResourceAsStream(String path
)
获取ServletContext对象
public void doGet(HttpServletRequest request
, HttpServletResponse response
)
throws ServletException
, IOException
{
ServletContext context
= this.getServletContext();
}
得到当前web应用的路径—重定向
public void doGet(HttpServletRequest request
, HttpServletResponse response
) throws ServletException
, IOException
{
ServletContext context
= this.getServletContext();
String contextPath
= context
.getContextPath();
System
.out
.println(contextPath
);
response
.sendRedirect(contextPath
+"/index.html");
}
得到web应用的初始化参数(全局)
public class ContextDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request
, HttpServletResponse response
)
throws ServletException
, IOException
{
ServletContext context
= this.getServletContext();
System
.out
.println("参数"+context
.getInitParameter("AAA"));
Enumeration
<String> enums
= context
.getInitParameterNames();
while(enums
.hasMoreElements()){
String paramName
= enums
.nextElement();
String paramValue
=context
.getInitParameter(paramName
);
System
.out
.println(paramName
+"="+paramValue
);
}
String path
= this.getServletConfig().getInitParameter("path");
System
.out
.println("path="+path
);
}
}
域对象有关的方法 域对象:作用是用于保存数据,获取数据。可以在不同的动态资源之间共享数据。所有域对象 HttpServletRequet 域对象 ServletContext域对象 HttpSession 域对象 PageContext域对象
void setAttribute(String name
, Object object
)
Object
getAttribute(String name
)
void removeAttribute(String name
)
转发(类似于重定向)
public class ForwardDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request
, HttpServletResponse response
) throws ServletException
, IOException
{
RequestDispatcher rd
= this.getServletContext().getRequestDispatcher("/GetDataServlet");
rd
.forward(request
, response
);
}
}
携带数据的转发
public class ForwardDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request
, HttpServletResponse response
) throws ServletException
, IOException
{
request
.setAttribute("name", "rose");
RequestDispatcher rd
= this.getServletContext().getRequestDispatcher("/GetDataServlet");
rd
.forward(request
, response
);
}
}
接收数据
public class GetDataServlet extends HttpServlet {
public void doGet(HttpServletRequest request
, HttpServletResponse response
) throws ServletException
, IOException
{
String name
= (String
)request
.getAttribute("name");
System
.out
.println("name=" + name
);
}
}
(6) 转发和重定向的区别
转发 a)地址栏不会改变 b)转发只能转发到当前web应用内的资源 c)可以在转发过程中,可以把数据保存到request域对象中重定向 a)地址栏会改变,变成重定向到地址。 b)重定向可以跳转到当前web应用,或其他web应用,甚至是外部域名网站。 c)不能再重定向的过程,把数据保存到request中。结论 如果要使用request域对象进行数据共享,只能用转发技术!!!