1.1 Web应用架构
1.1.1 Web应用模型
Web应用是基于B/S结构的,也就是浏览器/服务器结构。
基于B/S的应用程序部署在服务器端,客户端通过浏览器访问应用程序。如图1-1所示。
图1-1 服务器客户端模型
从图1-1中可以看到,客户端发送HTTP请求消息传给服务器,服务器将请求传递给服务器中所部署的Web应用程序,Web应用程序处理请求,并把响应的HTML页面通过服务器传给客户端显示。
在应用中,人们常用的浏览器有微软的IE,网景公司的Netscape Navigator,Mozilla的Firefox,以及目前国内用户常用的360浏览器等。
服务器分两种:Web服务器和Web应用服务器。
● Web服务器
可以解析HTTP协议。当Web服务器接收到一个HTTP请求,会返回一个HTTP响应,例如送回一个HTML页面。为了处理一个请求,Web服务器可以响应一个静态页面或图片,进行页面跳转,或者把动态响应的产生委托给一些其他的程序,如CGI脚本,JSP脚本,Servlets, ASP脚本,服务器端JavaScript,或者一些其他的服务器端技术。无论它们的目的如何,这些服务器端的程序通常产生一个HTML的响应来让浏览器可以浏览。
Web服务器不支持事务处理或数据库连接池。但它可以配置各种策略来实现容错性和可扩展性,如负载平衡,缓冲。
常用的Web服务器有IBM的HTTP Server,微软的IIS,还有Apache的Web服务器。本书将采用Apache Tomcat的Web服务器来部署各工程应用样例。
● Web应用服务器
可以通过各种协议,包括HTTP,把商业逻辑暴露给客户端应用程序。Web服务器主要是处理向浏览器发送HTML以供浏览,而Web应用服务器提供访问商业逻辑的途径以供客户端应用程序使用。应用程序使用这些商业逻辑就好像是调用对象的一个方法一样。应用程序服务器的客户端(包括有图形用户界面GUI的)可能会运行在一台PC、一个Web服务器甚至是其他的应用程序服务器上。
在大多数情形下,Web应用服务器是通过组件的应用程序接口(API)把商业逻辑暴露给客户端应用程序的,例如基于Java EE应用程序服务器的EJB组件模型。此外,Web应用服务器可以管理自己的资源,如安全、事务处理、资源池、消息等,就像Web服务器一样,Web应用服务器配置了多种可扩展和容错技术。
常用的Web应用服务器有IBM的WebSphere Application Server,BEA公司的WebLogic, Oracle的IAS,以及市场使用较为广泛的开源应用服务器Jboss,等等。
1.1.2 HTTP请求/响应模型
HTTP是一个属于应用层的面向对象的协议,由于简洁、快速的方式,适用于分布式超媒体信息系统。
HTTP协议基于请求/响应模型,因此存在两种HTTP消息:请求消息和响应消息。一个完整的HTTP会话过程如图1-2所示。
图1-2 HTTP请求响应模型
首先,客户端与Web服务器建立连接,通常通过默认的80端口:服务器Server侦听HTTP协议端口80等待客户端Browser的Socket连接请求;Browser向Server发出Socket连接请求,两边Socket建立连接。
建立连接后,客户端向Web服务器发送HTTP请求消息:Browser通过Socket连接的OutputStream向Server发送HTTP请求消息。
Web服务器处理请求,并将响应消息传送给客户端:Server通过Socket连接的InputStream得到请求,分析处理后通过Socket连接的OutputStream返回响应消息。
这样一个来回后,这个连接就关闭了(Browser/Server关闭Socket连接)。HTTP协议默认使用80端口进行访问。
HTTP协议是一个无状态的协议。也就是说,每当客户端访问Web服务器上某个Web页面时,都要建立与服务器的一个独立的连接。服务器不保留前一次访问的任何信息。Web服务器将客户端对某个页面的每次访问都当作相互无关的访问来处理;服务器不会自动保留客户机的状态信息。所以HTTP协议是一个无状态的协议。正因为如此,服务器端需要采取一定的措施来保留用户的状态数据,这就是状态管理。
请求消息和响应消息格式都包括起始行、零个或多个题头域、一个空行后的消息体。这里空行表示消息题头的结束,消息体是可选的。
请求消息的起始行就是请求行。它通常都是请求消息的首行,包含三个域:HTTP方法、通用资源标示符(URI)、HTTP协议版本。
尽管有几种HTTP方法可以从服务器中检索数据,但是最常用的通常仅有GET和POST方法。GET方法向服务器请求资源,由请求URI指示请求地址。如果URI指向生成数据的资源,如Servlet,则数据在响应消息中返回。如果要提交表单数据,可用POST方法。尽管GET方法可以在查询字符串中传递信息,但是一般使用POST方法明确传递服务器数据,这些数据可以被请求URI用来进行处理。
URI标志用来处理请求的资源。它可以是绝对路径,也可以是相对路径。无效的URI请求会返回错误代码(通常是404)。
HTTP请求协议版本告诉服务器:请求遵循了那个HTTP规范版本。
HTTP请求可能包含零个或多个题头域。请求题头域允许客户端向服务器传递有关请求和客户端本身的一些附加信息。请求消息和响应消息的题头域的格式是相同的,首先是题头域的名称,接着是冒号和值。如果对同一题头域规定了多个值,它们必须用逗号隔开。如表1-1是常见的题头域。
表1-1 HTTP消息题头域
下面来构造一个实例查看请求消息格式:编写一个Java应用程序HttpRequestViewer,该应用程序模拟Web服务器监听浏览器发出的HTTP请求,截获HTTP请求消息并在控制台将请求消息格式打印出来。详见【代码1-1】。
【代码1-1】 HttpRequestViewer.java。
/**此示例使用Java网络编程技术实现*/ public class HttpRequestViewer{ public static void main(String args[]){ try{ ServerSocket serversocket=new ServerSocket(8080);//服务器套接字, 绑定8080端口 Socket socket=serversocket.accept();//与客户端建立Socket连接 InputStream is=socket.getInputStream();//从套接字对象中得到输入流对象 InputStreamReader isr=new InputStreamReader(is);//字节流转换为字符流 BufferedReader br=new BufferedReader(isr);//包装成缓冲流 char charry[]=new char[1024];//定义缓冲区 int charrylength=br.read(charry);//读取内容 for(int i=0;i<charrylength;i++){//将读取内容循环输出到控制台 System.out.print(charry[i]); } br.close(); //关闭流对象 socket.close();serversocket.close();//关闭套接字连接 }catch(Exception e){ System.out.println("异常发生:"+e.getMessage()); } } }
编译并运行该Java应用程序,此时该应用程序将绑定8080端口进行监听。打开IE浏览器,在地址栏中向该模拟服务器发出资源请求,确保是向8080端口请求,例如,输入:http://localhost:8080/testweb/testhello.html,此时Java应用程序模拟的Web服务器正侦听8080端口,当与浏览器建立连接后,程序就会获取浏览器发出的请求消息,并打印在控制台上。可在控制台看到如图1-3所标示的请求消息格式。
图1-3 请求消息格式
一旦服务器接收和处理了请求消息,它就必须向客户端返回一条响应消息。响应消息的起始行称为状态行,此外同样包含零个或多个题头域,空行后一个可选的消息体。
HTTP响应的状态行包括响应消息所采用的HTTP协议版本,之后是响应状态码和状态描述。这些字段之间以空格隔开。状态码是三位数字值,用于描述服务器的响应状态。如表1-2所示是常见的HTTP响应状态码。
表1-2 HTTP响应状态码
下面同样来构造一个实例查看响应消息格式:编写一个Java应用程序HttpResponseViewer,模拟浏览器查看服务器返回的HTTP响应,在控制台将HTTP响应消息格式打印出来,详见【代码1-2】。
【代码1-2】 HttpResponseViewer.java。
public class HttpResponseViewer{ public static void main(String args[]){ try{ Socket socket=new Socket("localhost",8080); //构建套接字向服务 器发出连接请求 InputStreamReader isr=new InputStreamReader(socket. getInputStream()); BufferedReader br=new BufferedReader(isr); PrintWriter pw=new PrintWriter(socket.getOutputStream());// 从套接字中得到输出流并包装 pw.println("GET /index.html HTTP/1.1");//向服务器发送请求消息 pw.println("HOST:localhost:8080"); pw.println(); pw.flush(); char charry[]=new char[1024*100]; int charrylength=br.read(charry);//读取从服务器反馈的响应消息 for(int i=0;i<charrylength;i++){//在控制器台环把响应消息打印出来 System.out.print(charry[i]); } br.close(); pw.close(); socket.close(); }catch(Exception e){ System.out.println("异常发生:"+e.getMessage()); } } }
编译该Java应用程序得到字节码文件,首先启动一个Web服务器如Tomcat6.0,这个Web服务器默认会侦听8080端口的HTTP请求,接着使用Java解释器解释执行Java应用程序的字节码文件,模拟浏览器向Web服务器发出请求,并且接受Web服务器发出的响应消息。可以在控制台看到如图1-4所示的响应消息格式。
图1-4 HTTP响应消息格式
1.1.3 Web应用发展
早期的或者最简单的Web站点只提供Web页面的静态信息访问,如图1-5所示。也就是说,Web服务器所做的工作仅仅是将客户端发来的HTTP请求映射到文件系统的某个页面,然后把这个页面,通常就是普通的HTML页面传送给客户端。应用程序不会根据用户传入数据的不同而修改Web页面。
图1-5 静态Web
后来出现了Applet,Applet被称为客户端的Java小应用程序,它必须嵌入到网页中,由浏览器内嵌的JVM执行。当用户发出HTTP请求后,Applet随着Web页面一起被下载到客户端,Applet在浏览器的JVM中运行,能够提供动态的页面内容,从一定程度上扩展了Web服务器的功能,如图1-6所示。
图1-6 Applet
但是,基于安全性考虑,Applet被限制不能访问后台数据。这就出现了运行在服务器端的Servlet,如图1-7所示。
图1-7 Servlet
Servlet同样也是一段Java程序,称为服务器端Java小应用程序,它会根据用户提交的数据不同而产生不同的响应页面,从而提供与用户动态的交互。
Servlet是运行在服务器上的Web Container中,也就是Web容器。Web应用服务器提供Container,用于管理像Servlet这样的服务器端组件。
所以,当一个HTTP请求传到服务器,Web Server Plugin会检测这次请求的是静态资源还是动态资源。如果是静态资源,请求会传递给Web Server,Web Server将请求直接映射到文件系统中的某个页面,原封不动地将页面传回给客户端。但如果请求的是动态资源,Web Server Plugin会将请求传递给Web Container,Web Container会调用相应的Servlet,根据用户提交数据的不同,将动态内容传回给客户端。
由于这些动态内容是由Servlet通过硬编码方式输出HTML页面,这带来一个问题:就是仅使用Servlet往往会把业务逻辑和显示逻辑混合在一起。
为了更好地分离视图、控制和业务逻辑,JSP技术应运而生。通常用JSP页面来显示给用户的数据,用Servlet控制页面的流程,如图1-8所示。Servlet会根据请求信息的不同或应用程序逻辑的设定而调用相应的JSP页面。JSP和Servlet都可以调用JavaBean,从而产生动态内容。
图1-8 JSP
EJB即Enterprise JavaBean,它提供了对业务逻辑数据的封装。如图1-9所示,JavaBean可以通过Web Container来访问EJB,Java应用程序客户端也可以访问EJB。
图1-9 EJB的访问
当应用程序规模较大、有较多的访问请求时,就需要提供更好的可扩展性,更好的访问性能。如图1-10所示,需要将应用程序部署在服务器集群上,通过网络路由器等来实现负载均衡,从而提供更强的灵活性。
图1-10 Web扩展性