轉載自 https://my.oschina.net/liughDevelop/blog/1790893
作爲一個Java Web開發者,怎麼能不對Tomcat不感興趣呢?
於是,懷着一顆好奇的心,就想要摸一摸Tomcat的底層及實現原理。
那麼,Tomcat究竟在Web中承擔一個什麼樣的角色呢?
首先,當我們在瀏覽器輸入URL 比如http://www.baidu.com 的時候,瀏覽器發送一個Request去獲取 http://www.baidu.com 的html. Tomcat服務器把Response發送回給瀏覽器。
這個時候,瀏覽器就起到了一個收發Http請求的作用,同時,他還把Response的內容(大部分是HTML)解析成我們可以看的懂的樣式,也就是網頁,具體的我會再寫一篇HTTP協議的博客,分析其中的原理。
Tomcat在這個過程中,會把URL解析,找到對應的資源,再返回給瀏覽器,其中資源可以分爲動態資源和靜態資源。
動態資源就是Java中的Servlet,靜態資源就是html,css,js等無需Tomcat也可以返回給瀏覽器的資源。
也就是:用戶請求-->服務器尋找相應的資源-->服務器輸出對應的資源-->瀏覽器展示給用戶
我們先從簡單的,也就是解析靜態資源開始寫起吧。
代碼詳情看這個https://my.oschina.net/liughDevelop/blog/1790893
我主要是記錄下其中遇到的問題。
首先項目運行起來後,我在瀏覽器輸入http://localhost:8080
結果如下
好像結果不差,那我訪問下文件試試
哦豁,完蛋
這是爲什麼呢?
先看下到底有沒有讀取到本地文件,
輸出下輸入流,看看有沒有讀到
結果看,確實有讀取到本地文件,那既然讀到了,就是沒有成功顯示到瀏覽器上
這可就涉及到我的知識盲區了。。。
不過,還是得搞,一個字,盤他!
仔細分析下Response.java裏的這段代碼:
if (file.exists() && !file.isDirectory()) {
fis = new FileInputStream(file);
System.out.println(fis.read());
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch!=-1) {
output.write(bytes, 0, ch);
System.out.print(new String(bytes, 0, ch));
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
}else {
//文件不存在,返回給瀏覽器響應提示,這裏可以拼接HTML任何元素
String retMessage = "<h1>"+file.getName()+" file or directory not exists</h1>";
String returnMessage ="HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: "+retMessage.length()+"\r\n" +
"\r\n" +
retMessage;
output.write(returnMessage.getBytes());
}
返回瀏覽器的代碼就在這
分析可得:
如果文件存在,會運行這段代碼:
while (ch!=-1) {
output.write(bytes, 0, ch);
System.out.print(new String(bytes, 0, ch));
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
失敗,會運行這段:
String retMessage = "<h1>"+file.getName()+" file or directory not exists</h1>";
String returnMessage ="HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: "+retMessage.length()+"\r\n" +
"\r\n" +
retMessage;
output.write(returnMessage.getBytes());
是不是感覺少了什麼東東?
沒錯!響應頭
OK,加上響應頭後Response.java的代碼如下:
public class Response {
public static final int BUFFER_SIZE = 2048;
//瀏覽器訪問D盤的文件
private static final String WEB_ROOT ="D:";
private Request request;
private 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(WEB_ROOT, request.getUrL());
//如果文件存在,且不是個目錄
if (file.exists() && !file.isDirectory()) {
fis = new FileInputStream(file);
System.out.println(fis.read());
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch!=-1) {
String retMessage = new String(bytes, 0, ch);;
retMessage = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: "+retMessage.length()+"\r\n" +
"\r\n" +
retMessage;
output.write(retMessage.getBytes());
System.out.print(retMessage);
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
}else {
//文件不存在,返回給瀏覽器響應提示,這裏可以拼接HTML任何元素
String retMessage = "<h1>"+file.getName()+" file or directory not exists</h1>";
String returnMessage ="HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: "+retMessage.length()+"\r\n" +
"\r\n" +
retMessage;
output.write(returnMessage.getBytes());
}
}
catch (Exception e) {
System.out.println(e.toString() );
}
finally {
if (fis!=null)
fis.close();
}
}
}
OK,重新訪問下
好吧,雖然亂碼,不過。。。起碼返回是正常的。
不過這個亂碼始終是不行的,百度了一下發現:
當Java中使用 FileInputStream 讀取txt等文檔時,中文會產生亂碼。
附上解決地址:https://blog.csdn.net/ming2316780/article/details/48443697
修改後Response.java代碼如下:
import java.io.*;
/*
* Response的功能就是找到這個文件,使用Socket的outputStream把文件作爲字節流輸出給瀏覽器,就可以將我們的HTML顯示給用戶啦
*
*/
public class Response {
public static final int BUFFER_SIZE = 2048;
//瀏覽器訪問D盤的文件
private static final String WEB_ROOT ="D:";
private Request request;
private 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(WEB_ROOT, request.getUrL());
//如果文件存在,且不是個目錄
if (file.exists() && !file.isDirectory()) {
fis = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(fis,"UTF-8"); //最後的"GBK"根據文件屬性而定,如果不行,改成"UTF-8"試試
BufferedReader br = new BufferedReader(reader);
String line;
while ((line = br.readLine()) != null) {
String retMessage = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html;charset=utf-8\r\n" +
"Content-Length: "+ line.length() +"\r\n" +
"\r\n" +
line;
output.write(retMessage.getBytes());
System.out.print(retMessage);
}
}else {
//文件不存在,返回給瀏覽器響應提示,這裏可以拼接HTML任何元素
String retMessage = "<h1>"+file.getName()+" file or directory not exists</h1>";
String returnMessage ="HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html;charset=utf-8\r\n" +
"Content-Length: "+retMessage.length()+"\r\n" +
"\r\n" +
retMessage;
output.write(returnMessage.getBytes());
}
}
catch (Exception e) {
System.out.println(e.toString() );
}
finally {
if (fis!=null)
fis.close();
}
}
}
OK,跑起來試下,
好樣的,沒有亂碼了,不過感覺怪怪的,好像少了點東西
怎麼少了一些字。。。。。。
我滴媽耶,被瀏覽器造了嗎?
控制檯也輸出的是完整的鴨。。。
難道是Content-Length: 24這個的原因?
OK,把這個刪掉試試
再重新跑下 試試
OJBK,成功! 至於爲什麼Content-Length: 24會影響輸出不完整,我會再寫一篇博客進行分析,如果有哪位童鞋知道,也可以直接評論,博客有什麼不好的地方,歡迎大家指出來,我們一起交流交流。
Over~~~~~~~