- 浏览: 202486 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
qigeminghaofan:
第二个应用中说第一个不安全,熟悉servlet内部的程序员能向 ...
[How Tomcat Works]第2章 一个简单的Servlet容器 -
lliiqiang:
substring内存泄露问题只需要再加一个方法,让程序员明白 ...
优化变成了忧患:String.split引发的“内存泄露” -
tonghaoqi__:
必须点赞。。
如何控制War包访问Tomcat的内部实现类 -
jzzwy:
好文章 支持
Tomcat 5.5.26源代码分析——启动过程(一) -
wangzhewang:
牛!,希望更多分享!
Linux随机数发生器导致Apache进程全部Block的问题追查
译者 jarfield
博客 http://jarfield.javaeye.com
本章解释了Java Web 服务器是如何工作的。Web 服务器又被称为超文本传输 协议(Hypertext Transport Protocol , HTTP )服务器,因为它和客户端(通常是浏览器)使用HTTP 协议进行通信。基于Java 开 发的Web 服务器都使用到两个重要的类 :java.net.Socket 和 java.net.ServerSocket , 并通过HTTP 消息完成通信。因此,本章的开头就开始讨论HTTP 和这两个类。然后,继续介绍 本章附带的应用程序。
超文本传输协议 (HTTP )
HTTP 协议,允许Web 服务器和浏览器在Internet 上发送和接受数据。HTTP 是一种基于“请求-响应”模式的协议。客户端请求一 个文件(file ),服务器针对该请求给出响应。HTTP 使用可靠的TCP 连 接——默认端口是80 。HTTP的最初版本是HTTP/0.9 ,后来被HTTP/1.0 重 写。HTTP/1.0 的替代者是当前的HTTP/1.1 。HTTP/1.1 定 义在RFC 2612 中,可以从 http://www.w3.org/Protocols/HTTP/1.1/rfc2616.pdf 下载。
提示:本节只是简短地介绍HTTP
,目的是帮助你理解Web
服
务器发送的HTTP
消息。如果你想更深入得了解HTTP
,可以读读RFC
2616
。
HTTP
的
通信总是由客户端主动初始化:建立连接并发送HTTP
请求。Web
服务器从来不主动联系(contact
)
客户端,或者建立到客户端的回调(callback
)连接。无论客户端还是服务器,都可以随时(prematurely
)中断连接。例如,当你在下载文件时,点击浏览器的“停止”按钮,就关闭了浏览器和服务器之间的HTTP
连
接。
HTTP 请求
HTTP 请求包含3 个组成部分:
- Method-Uniform Resource Identifier (URI)-Protocol/Version
- Request headers (请求头部)
- Entity body (实体主体)
下面是HTTP 请求的一个例子:
POST /examples/default.jsp HTTP/1.1 Accept: text/plain; text/html Accept-Language: en-gb Connection: Keep-Alive Host: localhost User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98) Content-Length: 33 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate lastName=Franks&firstName=Michael
Method-URI-Protocol/Version 是请求的第一行
POST /examples/default.jsp HTTP/1.1
POST
是Method
,/examples/default.jsp
是URI
,HTTP/1.1
就是Protocol/Version
。
每个HTTP
请求都可以使用HTTP
标
准中众多Method
中的一个。HTTP/1.1
共支持7
种Method
: GET
,
POST
, HEAD
,
OPTIONS
, PUT
, DELETE
和TRACE
。GET
和POST
是互联网应用使用最普遍的Method
。
URI
标
识了互联网上的资源。URI
的解析通常都是相对与服务器根目录的。因此,URI
总是从正斜线/
开
始。统一资源定位器(Uniform Resource Locator
, URL
)实际上是一种URI
(参
见
http://www.ietf.org/rfc/rfc2396.txt
)。Protocol
version
表示使用了哪个版本的HTTP
协议。
Request header
包含了关于客户端环境和entity body的有用信息
。例如,headers
可能包括浏览器的语言,entity body
的
长度等等。Header
之间通过回车/换行符(CRLF
)分隔。
在headers
和entity body
之
间,是一个空行(CRLF
)。这个CRLF
对于HTTP
请求内容的格式是相当重要的,它告诉HTTP
服务器:entify body
从哪开始。在一些介绍互联网编程的书中,该CRLF
被认为是HTTP
请求的第4
个组成部分。
在前面的HTTP
请求中,entify
body
仅仅只有这一行:
lastName=Franks&firstName=Michael
这里只是一个例子,实际的HTTP
请求中,entity body
当然可以更长一些。
HTTP 响应
和HTTP请求一样,HTTP 响应也包含3 个组成部分:
- Protocol—Status code—Description
- Response headers (响应头部)
- Entity body (实 体主体)
下面是HTTP 响 应的一个例子:
HTTP/1.1 200 OK Server: Microsoft-IIS/4.0 Date: Mon, 5 Jan 2004 13:13:33 GMT Content-Type: text/html Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT Content-Length: 112 <html> <head> <title>HTTP Response Example</title> </head> <body> Welcome to Brainy Software </body> </html>
HTTP
响应的第一行类似于HTTP
请求的第一行。第一行告诉你:使用的HTTP
版本是HTTP/1.1
,请求处理成功了(200
= 成功),一切运行正常。
响应headers
和请求headers
类似,包含了很多有用的信息。响应数据中的entity body
是响应本身的HTML
内容。Headers
和entity body
之间通过CRLF
分隔。
Socket 类
套接字是网络连接的一个端点(endpoint
)。
应用程序使用套接字从网络上读取数据、向网络写入数据。两台不同机器上的应用,在同一个连接上以字节流的格式向(从)对方发送(接收)数据。
为了向一个应用发送消息,你需要知道该应用的IP
地址和端口。在Java
中,套接字用
java.net.Socket
类来表示。
你可以使用
Socket
类众多
构造函数中的一个来创建
套接字
对象。其中一个构造函数接收主机名和端口作为参数:
public Socket (java.lang.String host, int port)
其中,host
是远程机器的名称或IP
地
址,port
是远程应用的端口号。例如,要连接上
yahoo.com
的80
端口,你可以创建下面的
Socket
对象:
new Socket("yahoo.com", 80);
只要你成功创建了
Socket
的一个实例,就可以使用它发送和读取字节流。如果要发送字节流,你可以调用
Socket
类的
getOutputStream
方法获取一个
java.io.OutputStream
对象。如果要发送文本信息,你可以将上述
java.io.OutputStream
对象包装成一个
java.io.PrintWriter
对象。如果要读取字节流,你可以调用Socket
类的
getInputStream
方法获取一个
java.io.InputStream
对象
下面的代码片段创建了一个能够与本地HTTP
服务器(127.0.0.1
表
示本地主机)通信的
Socket
对象,发送了一个HTTP
请
求,并
从服务器
接收了HTTP
响
应。另外,这段代码还创建了一个
StringBuffer
对象来存储响应数据,并将其打印在控制台上。
Socket socket = new Socket("127.0.0.1", "8080"); OutputStream os = socket.getOutputStream(); boolean autoflush = true; PrintWriter out = new PrintWriter(socket.getOutputStream(), autoflush); BufferedReader in = new BufferedReader(new InputStreamReader( socket.getInputstream() )); // send an HTTP request to the web server out.println("GET /index.jsp HTTP/1.1"); out.println("Host: localhost:8080"); out.println("Connection: Close"); out.println(); // read the response boolean loop = true; StringBuffer sb = new StringBuffer(8096); while (loop) { if ( in.ready() ) { int i=0; while (i!=-1) { i = in.read(); sb.append((char) i); } loop = false; } Thread.currentThread().sleep(50); } // display the response to the out console System.out.println(sb.toString()); socket.close();
需要注意的是,为了从Web
服务器得到恰当
的响应,你发送的HTTP
请求必须遵守HTTP
协议。如果你读了
前一节,超文本传输协议(HTTP
),应该就会理解上面代码中的HTTP
请求。
提示:你可以使用本书源代码中的com.brainysoftware.pyrmont.util.HttpSniffer
类发送HTTP
请求和显示HTTP
响
应。为了使用这个Java
程序,你必须连接到Internet
。不过,提醒一句,如果你在防火墙后面,那么这个类可能不能正常工作。
ServerSocket 类
前面介绍的Socket
类,代表的是客户端套接字,即当你为了连接到远程服务程序而创建的
套接字
对象。现在,如果你想要实现一个服务器程序,比如HTTP
服
务器或FTP
服务器,你需要一种不同的做法。因为,服务器程序必须一直驻守,
它不知道客户端何时会连接过来。为了使你的程序能够驻守,你需要使用
java.net.ServerSocket
类。这是服务器端socket
的一个实现类。
ServerSocket
类和
Socket
类并不相同。服务器套接字的职责是等待来自客户端的连接请求。当服务器套接字收到一个连接请求后,创建一个
Socket
对象来
与客户端通信。 为了创建服务器套接字,你需要使用
ServerSocket
类提供的4
个
构造函数之一。你需要指定服务器套接字将要监听的IP
地址和端口。通常,IP
地址是127.0.0.1
,表示服务器套接字将监听本地机器。服务器套接字监听的IP
地址被称为绑定地址
(binding address
)。服务器套接字的另一个重要属性是backlog
,服务器套接字有一个保存尚未处理的连接请求的队列,backlog
就是该队列的的最大长度。如果达到最大长度,服务器套接字将拒绝新的连接请
求。
下面是
ServerSocket
类的一个构造函数原型:
public ServerSocket(int port, int backLog, InetAddress bindingAddress);
注意这个构造函数,binding address
必须是一个
java.net.InetAddress
对象。创建
InetAddress
对象的一个简单方法就是调用该类的静态方法
getByName
,
并把主机名作为
String
对象传给该方法,就像下面这样:
InetAddress.getByName("127.0.0.1");
下面这行代码创建了一个监听本地8080
端
口的、backlog
为1
的ServerSocket
对象。
new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
有了ServerSocket 对象后,你就可以告诉它:在指定的端口上监听绑定地址的连接请求吧。告 诉的办法就是调用 ServerSocket 的 accept 方法。当有一个连接请求到达时,该方法就会返回,返回值是一个 Socket 对 象。这个Socket 对象就像 前一节, “Socket 类”,描述的那样,可以用来向(从)客户端发送(读取)数据。实际上,accept 方法也是本章应用程序唯一使用的( ServerSocket 类的)方法。
应用程序
本章的应用程序是一个Web服务器程序,放在 ex01.pyrmont 包中,由3 个类组成:
- HttpServer
- Request
- Response
本章应用程序的入口(静态的
main
方法)在
HttpServer
类中。
main
方法创建了一个
HttpServer
对象,并调用了它的
await
方法。人如其名,
await
方法在指定端口上等待HTTP
请
求,然后处理HTTP
请求,最后将HTTP
响应发送回客户端。而且,
await
方法保持等待,只有接收到
shutdown
命令,才退出运行。该应用只能发
送静态资源,诸如特性目录下的HTTP
文件和图像文件。同时,还在控制台上显
示HTTP
请求的字节流。然而,该应用不向浏览器发送任何header
(date
、cookies
等)。
下面各小节,我们将会看一看这3
个类。
HttpServer 类
HttpServer
类
表示了一个Web
服务器,代码在
Listing 1.1
中。需要注意的是,为了节省篇幅,await
方法没被列在
Listing 1.1
中,可以在
Listing 1.2
中找到。
Listing
1.1: The HttpServer class
package ex01.pyrmont; import java.net.Socket; import java.net.ServerSocket; import java.net.InetAddress; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import java.io.File; public class HttpServer { /** WEB_ROOT is the directory where our HTML and other files reside. * For this package, WEB_ROOT is the "webroot" directory under the * working directory. * The working directory is the location in the file system * from where the java command was invoked. */ public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; // shutdown command private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; // the shutdown command received private boolean shutdown = false; public static void main(String[] args) { HttpServer server = new HttpServer(); server.await(); } public void await() { ... } }
Listing
1.2: The HttpServer class's await method
public void await() { ServerSocket serverSocket = null; int port = 8080; try { serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // Loop waiting for a request while (!shutdown) { Socket socket = null; InputStream input = null; OutputStream output = null; try { socket = serverSocket.accept(); input = socket.getInputStream(); output = socket.getOutputStream(); // create Request object and parse Request request = new Request(input); request.parse(); // create Response object Response response = new Response(output); response.setRequest(request); response.sendStaticResource(); // Close the socket socket.close(); //check if the previous URI is a shutdown command shutdown = request.getUri().equals(SHUTDOWN_COMMAND); } catch (Exception e) { e.printStackTrace (); continue; } } }
这个Web 服务器可以提供静态资源服务,可访问的资源位于 public static final WEB_ROOT 表示的 目录及子 目录下。WEB_ROOT 是这样初始化的:
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
这段代码中有一个名为webroot
的目录,该目录
包含了可以用于测试该应用的的静态资源。你还可以从该目录下找到几个用于测试下一章应用的servlet
。
如果要请求一个静态资源,你可以在浏览器的地址栏中敲入以下URL
:
http://machineName:port/staticResource
如果你从另一台机器上发送请求,
machineName
应该是该应用所在机器的主机名或IP
地址。如果你的浏览器运行在同一台机器上,可以使用
localhost
作为
machineName
。端口是8080
,
staticResource
是被请求的文件(静态资源)名,该文件必须位于
WEB_ROOT
下。
例如,你在同一台机器上测试该应用,想让HttpServer
发送文件index.html
,你可以使用下面的URL
:
如果要停止服务器,你可以通过特定的URL从浏览器发送shutdown命令:host:port的后面加上预先定义的、表示shutdown的字符串即可。
HttpServer
类的静态常量
SHUTDOWN
定义了
shutdown命令:
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
因此,如果要停止服务器,你可以使用下面的URL
:
http://localhost:8080/SHUTDOWN
现在,我们看一看
Listing 1.2
中的await
方
法。
方法名使用await
而不用wait
,是因为wait
是java.lang.Object
类中一个重要的、与多线程紧密相关的方法。
await
方法首先创建了一个ServerSocket
对
象,然后进入一个
while
循环。
serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); ... // Loop waiting for a request while (!shutdown) { ... }
while
循环中的代码运行到
ServerSocket
的
accept
方法就停止下来,直到在8080
端
口上收到HTTP
请求才返回:
socket = serverSocket.accept();
收到一个请求后, await 方法从 accept 方法返回的 Socket 对象中获取了 java.io.InputStream 对象和 java.io.OutputStream 对象。
input = socket.getInputStream(); output = socket.getOutputStream();
await 方法然后创建了一个 ex01.pyrmont.Request 对象,并调用它的 parse 方法来解析HTTP请求的原始数据(raw data )。
// create Request object and parse Request request = new Request(input); request.parse ();
之后,
await
方法创建了一个
Response
对象,将上面的
Request
对象设置成
Response
对象的成员,并调用
Response
对象的
sendStaticResponse
方法。
// create Response object Response response = new Response(output); response.setRequest(request); response.sendStaticResource();
最后, await 方法关闭 了 Socket 对象,并调用了 Request 对象的 getUri 方法,检查本次HTTP 请 求的URI 似乎否是shutdown 命 令。如果是(shutdown 命令)的话, shutdown 变 量会被设置成 true ,从而程序将退出 while 循环。
// Close the socket socket.close (); //check if the previous URI is a shutdown command shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
Request 类
ex01.pyrmont.Request
类代表了HTTP
请
求。要创建
Reuqest
对象,我们可以先从处理客户端通信的
Socket
对象中
获得的
InputStream
对象,然后将其作为参数调用
Request
类的构造函数。通过调用
InputStream
对象的
read
方法簇之一,就可以获取HTTP
请求的原始数据。
Listing 1.3
列出了
Request
类的代码。
Request
类有两个public
方法,
parse
和
getUri
,
Listing
1.4
和
Listing 1.5
分别列出了这两个方法的代码。
Listing
1.3: The Request class
package ex01.pyrmont; import java.io.InputStream; import java.io.IOException; public class Request { private InputStream input; private String uri; public Request(InputStream input) { this.input = input; } public void parse() { ... } private String parseUri(String requestString) { ... } public String getUri() { return uri; } }
Listing 1.4: The Request
class's parse method
public void parse() { // Read a set of characters from the socket StringBuffer request = new StringBuffer(2048); int i; byte[] buffer = new byte[2048]; try { i = input.read(buffer); } catch (IOException e) { e.printStackTrace(); i = -1; } for (int j=0; j<i; j++) { request.append((char) buffer[j]); } System.out.print(request.toString()); uri = parseUri(request.toString()); }
Listing 1.5:
the Request class's parseUri method
private String parseUri(String requestString) { int index1, index2; index1 = requestString.indexOf(' '); if (index1 != -1) { index2 = requestString.indexOf(' ', index1 + 1); if (index2 > index1) return requestString.substring(index1 + 1, index2); } return null; }
除了解析HTTP
请求的原始数据,
parse
方法也
没做更多的事情。该方法从HTTP
请求中获取的唯一信息,就是通过调用private
方法
parseUri
解析出的URI
。
parseUri
方
法将HTTP
请求的URI
存
储在成员变量
uri
中。调用public
方法
getUri
可以返
回HTTP
请求的URI
。
提示:第3
章及后续章节将对HTTP
请求原始数据进行更多的处理。
为了理解
parse
和
parseUri
方法是如何工作的,你需要知道HTTP
请求的协议格式,这在
前面小节,“超文本传输协议(HTTP
)”,已经讨论过。本章,我们只对HTTP
请求的第一部分,请求行(request line
),感兴趣。请求行以method
标记开头,后面是请求URI
和协议版本,最后以回车换行符(CRLF
)结束。请求行中的元素是以空格分隔的。例如,使用GET
方法请求index.html
的请求行如下所示:
GET /index.html HTTP/1.1
parse
方法从传给
Request
对象的
InputStream
对象中读取整个字节流,并保存在字节数组
buffer
中。然后,使用
buffer
中的字节数据创建一个名为
request
的
StringBuffer
对象,并将
StringBuffer
对象的
String
表示(representation
)
传给
parseUri
方法。
parse
方法的代码列在
Listing 1.4
中。
parseUri
方法负责从请求行中获取URI
。
Listing 1.5
列出了
parseUri
方法的代码。
parseUri
方法在请求行中搜索第一个和第二个空格,获取(两个空格)之间的URI
。
Response 类
ex01.pyrmont.Response
类代表了HTTP
响应数据,Listing 1.6
列出了其代码。
Listing
1.6: The Response class
package ex01.pyrmont; import java.io.OutputStream; import java.io.IOException; import java.io.FileInputStream; import java.io.File; /* HTTP Response = Status-Line *(( general-header | response-header | entity-header ) CRLF) CRLF [ message-body ] Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ public class Response { private static final int BUFFER_SIZE = 1024; Request request; OutputStream output; public Response(OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } public void sendStaticResource() throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; try { File file = new File(HttpServer.WEB_ROOT, request.getUri()); if (file.exists()) { fis = new FileInputStream(file); int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch!=-1) { output.write(bytes, 0, ch); ch = fis.read(bytes, 0, BUFFER_SIZE); } } else { // file not found String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>"; output.write(errorMessage.getBytes()); } } catch (Exception e) { // thrown if cannot instantiate a File object System.out.println(e.toString() ); } finally { if (fis!=null) fis.close(); } } }
我们首先注意到,该类的构造函数接收一个
java.io.OutputStream
对象作为参数,如下所示。
public Response(OutputStream output) { this.output = output; }
HttpServer
类的
await
方法从
Socket
对象中获取
OutputStream
对象,将其作为参数构造了一个
Response
对象。
Response
类
有两个
public
方法:
setRequest
和
sendStaticResource
。
setRequest
方法用来将
Request
对象设置成
Response
对象的成员变量。
sendStaticResource
方法用来发送静态资源,比如HTML
文件。该方法首先将父路径和子路径传递给
java.io.File
的构造函数,创建一个File
对
象。
File file = new File(HttpServer.WEB_ROOT, request.getUri());
然后检查该文件是否存在。如果存在,那么 sendStaticResource 方法以File 对 象为参数构造一个 java.io.FileInputStream 对象。接着,调用 FileInputStream 对象的 read 方法,并向 OutputStream 对象 output 写入字节数组。请注意,这种情况下,静态资源的内容是作为原始数据发送给浏览器的。
if (file.exists()) { fis = new FileInputstream(file); int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch!=-1) { output.write(bytes, 0, ch); ch = fis.read(bytes, 0, BUFFER_SIZE); } }
如果文件不存在,那么 sendStaticResource 方法就将错误信息发送给浏览器。
String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>"; output.write(errorMessage.getBytes());
运行应用程序
要从工作目录运行该应用,需要敲入下面的命令:
java ex01.pyrmont.HttpServer
要测试该应用,可以打开浏览器,在地址栏敲入下面的URL
:
http://localhost:8080/index.html
正如Figure 1.1
所示,你会看到index.html
显示在浏览器(原图是IE6
,
这里是译者的IE8
)中。
Figure 1.1: The output from the web server
在控制台上,你可以看到类似于下面的HTTP
请求:
GET /index.html HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms- powerpoint, application/x-shockwave-flash, application/pdf, */* Accept-Language: en-us Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) Host: localhost:8080 Connection: Keep-Alive GET /images/logo.gif HTTP/1.1 Accept: */* Referer: http://localhost:8080/index.html Accept-Language: en-us Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) Host: localhost:8080 Connection: Keep-Alive
总结
从本章你已经看到了简单的Web 服务器是如 何工作的。本章附带的应用只包括3 个类,功能还不完整。无论如何,该应用仍是 一个很好的学习工具。下一章,我们将讨论对动态内容(dynamic content ) 的处理。
评论
在index.html 中写入
<title>HTTP Response Example</title>
lz 今天看你的实例 。今天发现html 里面有个问题。在titl 中如果写HTTP空格,这样的话body内容是不会显示的。 。
Response 中读取文件问题?
不是如果不是HTTP开头 加空格就没有问题的。
在index.html 中写入
<title>HTTP Response Example</title>
lz 今天看你的实例 。今天发现html 里面有个问题。在titl 中如果写HTTP空格,这样的话body内容是不会显示的。 。
Response 中读取文件问题?
+ "Content-Type: text/html\r\n"
+ "Content-Length: 25\r\n" + "\r\n" +
"<h1>File Not Foundsa</h1>";
如果改成:
errorMessage = "it is error!!";
IE会显示 "it is error!!",也就是说没有reponse报文头,浏览器也是可以显示的.
我用httpWatch看到,返回的报文的确没有头部.
可以给个QQ之类的联系方式吗,最近在研究TOMCAT,想多多请教.我们公司就在你们前面,呵呵
在这里起什么作用,为什么去除之后就收不到结果,服务端如何判断请求头已发送完毕?
Connection: Close 是一个头部,告诉服务端:不要保持连接,处理完这个请求后直接关闭连接即可。
服务端通过最后一个空行来判断请求头发送完毕。
在这里起什么作用,为什么去除之后就收不到结果,服务端如何判断请求头已发送完毕?
发表评论
-
如何控制War包访问Tomcat的内部实现类
2010-12-14 21:56 6315Tomcat默认部署了Manager应 ... -
[How Tomcat Works]第4章 Tomcat默认连接器
2010-06-29 20:17 8547译者 jarfield 博 客 ht ... -
[How Tomcat Works]第3章 连接器(二)
2010-04-10 22:50 7829译者 jarfield 博客 http://j ... -
[How Tomcat Works]第3章 连接器(一)
2010-04-10 21:55 8718译者 jarfield 博客 http://j ... -
Tomcat 5.5.26源代码分析——启动过程(二)
2010-03-25 14:38 7778init方法 Catalina_Home和Cat ... -
Tomcat 5.5.26源代码分析——启动过程(一)
2010-03-25 14:30 5032main方法 第一阶段 第二阶段 ... -
[How Tomcat Works]第2章 一个简单的Servlet容器
2010-03-14 00:43 4143译者 jarfield 博客 http: ... -
Tomcat 5.5.26的网络构建指南
2010-02-27 00:44 33471. 安装JDK ... -
[How Tomcat Works]第0章 介绍
2010-02-24 19:09 3222译者 jarfield 博客 ... -
Eclipse远程调试Tomcat
2010-01-24 20:24 4824最近,一直在研究Tomcat的工作内幕,主要的方法就是参考《H ...
相关推荐
本篇文章将深入探讨Tomcat,一个广泛使用的Java Web服务器,通过翻译分析"How Tomcat Works"一书的前四章内容,来理解其工作机制。 首先,我们要了解Tomcat的基本架构。Tomcat是Apache软件基金会的Jakarta项目中的...
《译How Tomcat Works(第二章)》这篇文章主要讲解了Apache Tomcat服务器的工作原理,它是一个开源的Java Servlet容器,广泛用于部署Web应用程序。在这一章中,我们将深入探讨Tomcat如何处理HTTP请求,以及其内部架构...
《How Tomcat Works》是...总的来说,《How Tomcat Works》是学习和理解Tomcat内部运作机制的重要资源,配合源码分析,能帮助开发者提升对Java Web服务器的理解和应用能力,从而更好地设计和优化高性能的Web应用程序。
《How Tomcat Works》这本书是理解Apache Tomcat服务器工作原理的重要资源,第三章主要探讨了Tomcat的架构和核心组件。以下是对这部分内容的详细解读: Tomcat作为一款开源的Java Servlet容器,其核心功能是解析...
Apache Tomcat是一个开源的Java Servlet容器,它实现了Java Servlet和JavaServer Pages技术规范,提供了Java Web服务器的功能。对于Java Web开发者,尤其是那些希望深入了解Web容器工作原理的学习者而言,这本书是一...
《译How Tomcat Works(第一章)》这篇文章是关于Apache Tomcat服务器的工作原理的翻译,它主要探讨了Tomcat如何处理HTTP请求以及内部架构的关键组成部分。Tomcat是一款开源的Java Servlet容器,广泛用于部署Java Web...
本篇文章将深入探讨Tomcat的工作机制,基于《How Tomcat Works》一书的第7至9章进行翻译和分析。 第7章主要讲解了Tomcat的启动过程和服务器的配置。Tomcat启动时,首先读取主配置文件`server.xml`,这个文件定义了...
通过阅读和分析《How Tomcat Works》的第12章,我们可以更深入地了解Tomcat如何处理请求,管理Web应用,并为开发者提供一个强大的平台来构建和运行Java Web应用程序。这有助于我们更好地利用Tomcat的特性,提高应用...
《WEB服务器工作机制由浅至深(8):【How Tomcat Works】第14章Server和Service》 在深入探讨Web服务器的工作机制时,Tomcat作为Apache软件基金会的开源Java Servlet容器,扮演着至关重要的角色。本章将聚焦于Tomcat...
通过对《How Tomcat Works》一书第11章的翻译与分析,我们将揭示StandardWrapper如何工作,以及它对整个Web应用的影响。 首先,我们需要了解Servlet的生命周期。Servlet在Web应用中扮演着动态处理请求的角色,它们...
《译How Tomcat Works(第四章)》这篇文章深入解析了Apache Tomcat服务器的工作原理,主要聚焦于Tomcat的内部机制,对于理解Web应用容器的运行方式具有重要意义。Tomcat是Java Servlet和JavaServer Pages(JSP)...
在《How Tomcat Works》一书中,第10章主要介绍了Tomcat的内部工作流程。Tomcat接收到HTTP请求后,首先会通过网络层处理数据包,然后进入服务层解析请求。这一阶段涉及到解码URL、解析请求头和提取参数等步骤。接着...
本文将深入探讨Tomcat的工作机制,基于"How Tomcat Works"的第五章和第六章进行翻译和分析。 第五章主要讨论了Tomcat的生命周期管理和容器概念。在Tomcat中,每个应用都有一个对应的Context,它管理Servlet的加载、...
【WEB服务器工作机制由浅至深(9):【How Tomcat Works】第16章 关闭钩子以及之后的章节简述】 在深入探讨Tomcat服务器的工作机制时,我们来到了第16章,这一章主要讨论了“关闭钩子”(Shutdown Hooks)的概念及其在...
《译How Tomcat Works(第三章)》这篇文章深入解析了Apache Tomcat服务器的工作原理,Tomcat作为开源的Java Servlet容器,是许多Web应用程序的基础。在本章中,我们将聚焦于Tomcat如何处理HTTP请求,以及它如何加载和...
本篇文章将深入剖析"HowTomcatWorks",帮助读者全面理解Tomcat的内部工作机制。 1. **Tomcat架构概述** Tomcat由一系列组件构成,包括Catalina(核心Servlet容器)、Jasper(JSP引擎)、 Coyote(HTTP/HTTPS连接器...
Tomcat的源码是开放的,这对于开发者来说是一个宝贵的资源,可以学习到如何设计和实现一个高性能的WEB服务器。同时,工具如JMX(Java Management Extensions)可以帮助监控和管理Tomcat的运行状态,包括Engine、Host...