淺談web服務(wù)器項(xiàng)目中request請(qǐng)求和response的相關(guān)響應(yīng)處理
我們經(jīng)常使用別人的服務(wù)器進(jìn)行構(gòu)建網(wǎng)站,現(xiàn)在我們就自己來寫一個(gè)自己的服務(wù)來使用。
準(zhǔn)備工作:下載所需的題材及文檔
一、request請(qǐng)求獲取
1、了解request請(qǐng)求
在寫服務(wù)器之前,我們需要知道客戶端發(fā)送給我們哪些信息?以及要求我們返回哪些信息?經(jīng)過測(cè)試我們能夠知道用戶客戶端發(fā)送的信息有以下幾點(diǎn):
客戶端發(fā)送到服務(wù)器端的請(qǐng)求消息,我們稱之為請(qǐng)求(request),其實(shí)就是一個(gè)按照http協(xié)議的規(guī)則拼接而成的字符串,Request請(qǐng)求消息包含三部分: 請(qǐng)求行 消息報(bào)頭 請(qǐng)求正文
第一部 請(qǐng)求行
格式:
Method Request-URI HTTP-Version CRLF
各部分分別為:
Method表示請(qǐng)求方法;一般為GET或者POST ;Request-URI是一個(gè)統(tǒng)一資源標(biāo)識(shí)符; HTTP-Version表示請(qǐng)求的HTTP協(xié)議版本; CRLF表示回車和換行
例如:
GET /test.html HTTP/1.1
第二部 消息報(bào)頭 http header
例如:
GET /test.html HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,en;q=0.8,zh;q=0.5,en-US;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
第三部 請(qǐng)求正文 http body
請(qǐng)求頭和請(qǐng)求正文之間是一個(gè)空行,這個(gè)行非常重要,它表示請(qǐng)求頭已經(jīng)結(jié)束,接下來的是請(qǐng)求正文。請(qǐng)求正文中可以包含客戶提交的字符串信息
注意:在第二部分header和第三部分body之間有個(gè)空行,除非沒有請(qǐng)求正文(如果你想要親自看到效果,請(qǐng)參考:瀏覽器中GET和POST的區(qū)別),這是因?yàn)橛脩粼跒g覽網(wǎng)頁時(shí)提交給服務(wù)器的信息是不同的
2、實(shí)現(xiàn)
經(jīng)過以上分析,我們就能夠清楚的知道,客戶端發(fā)送給服務(wù)器的請(qǐng)求,請(qǐng)求信息有使用的協(xié)議、請(qǐng)求的方法、請(qǐng)求的資源路徑、請(qǐng)求的消息報(bào)頭、判斷請(qǐng)求的內(nèi)容是否為靜態(tài)資源、判斷請(qǐng)求的內(nèi)容是否為動(dòng)態(tài)資源、判斷是否為空請(qǐng)求,為了使用的方便,我們需要將其封裝起來,總不能使用一次讀取一次吧,這樣做實(shí)在是太浪費(fèi)系統(tǒng)資源與時(shí)間了,如下代碼,就是一個(gè)接口類,用于獲取客戶端發(fā)送過來的屬性
package com.sample.http;
import java.util.Map;
// http協(xié)議的請(qǐng)求
public interface HttpRequest {
//獲得請(qǐng)求的協(xié)議
public String getProtocol();
//獲得請(qǐng)求的方法
public String getRequestMethod();
//獲得請(qǐng)求的路徑
public String getRequestPath();
//獲得請(qǐng)求的消息報(bào)頭
public Map<String,String> getRequestHeader();
//根據(jù)參數(shù)的名字獲得請(qǐng)求帶過來的參數(shù)值
public String getParameter(String parameterName);
//判斷當(dāng)前請(qǐng)求的否是靜態(tài)資源
public boolean isStaticResource();
//判斷當(dāng)前請(qǐng)求的否是動(dòng)態(tài)資源
public boolean isDynamicResource();
//判斷當(dāng)前請(qǐng)求的否是為空請(qǐng)求(有些瀏覽器會(huì)自動(dòng)發(fā)送空請(qǐng)求)
public boolean isNullRequest();
}
有了接口類之后,我們就可以創(chuàng)建類進(jìn)行實(shí)現(xiàn),下面就是實(shí)現(xiàn)類,用于對(duì)各個(gè)方法進(jìn)行處理:
package com.sample.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class HttpRequestImpl implements HttpRequest{
//客戶端的Socket
private Socket s;
private InputStream is=null;//輸入流
private BufferedReader br=null;
private HashMap<String,String> hmHeader=new HashMap<String,String>();//消息報(bào)頭
private HashMap<String,String> hmparameters=new HashMap<String, String>();//參數(shù)集合
private boolean isNullRequest=false;//是否為空請(qǐng)求,默認(rèn)false
private String protocol=null;//請(qǐng)求協(xié)議
private String requestMethod=null;//請(qǐng)求方法
private String requestPath=null;//請(qǐng)求路徑
public HttpRequestImpl(Socket s) {
this.s=s;
getInfos();//調(diào)用方法
}
private void getInfos()//定義一個(gè)方法,用于處理獲取的客戶端信息
{
try {
is=s.getInputStream();
br=new BufferedReader(new InputStreamReader(is));
//解析第一行
String str;
str=br.readLine();//readLine使用回車換行判斷一行是否結(jié)束
if(str==null)
{
isNullRequest=true;
return;
}
parseRequestMethodPathProtocol(str);//調(diào)用自己創(chuàng)建在本類里邊的方法處理第一行信息,方法在后面
//解析第二行---第八行
String header=null;
//判斷是否結(jié)束,如果結(jié)束就退出,這里的判斷按較為饒人
//首先應(yīng)該明確br.readLine()的內(nèi)容,當(dāng)為true是對(duì)應(yīng)的情況
//也就是說當(dāng)“”(中間沒有空格)與br.readLine()相等時(shí),就進(jìn)入到while中
while(!"".equals((header=br.readLine()))){
parseRequestHeader(header);
}
//post和get
if(br.ready())//post//POST提交方式判斷,如果還有下一行就繼續(xù)讀取信息
{
char[] buf=new char[1024];
int len=br.read(buf);//使用字節(jié)進(jìn)行讀取,因?yàn)檫@一行沒有回車換行,readLine無法判斷是否結(jié)束
String parameter=new String(buf,0,len);
parseRequestParamByPost(parameter);//調(diào)用自己創(chuàng)建在本類里邊的方法處理POST方式提交的正文信息
}
else
{//get,get參數(shù)的位置在第一行連接處
parseRequestParamByGet(requestPath);//調(diào)用自己創(chuàng)建在本類里邊的方法處理GET方式提交的正文信息
}
} catch (Exception e) {
e.printStackTrace();
}
}
//GET方法處理
private void parseRequestParamByGet(String requestPath2) {
String []str1=requestPath2.split("[?]");//使用“?”分割字符串
if(str1.length==2)
{
parseRequestParamByPost(str1[1]);
}
this.requestPath=str1[0];
}
//POST方法處理
private void parseRequestParamByPost(String parameter) {
String[] strs=parameter.split("&");
if(strs.length>=1)
{
for(String str:strs)
{
String [] sp=str.split("=");
hmparameters.put(sp[0],sp[1]);
}
}
}
//解析第二行到第八行
private void parseRequestHeader(String header) throws Exception{
String[] headHost=header.split(": ");
if(headHost.length!=2)
{
throw new Exception("消息報(bào)頭異常,請(qǐng)重新提交");
}
hmHeader.put(headHost[0],headHost[1]);
}
//解析第一行
private void parseRequestMethodPathProtocol(String str) throws Exception {
String[] protocolMethodPath=new String[3];//由于第一行含有三個(gè)內(nèi)容,分割后需要三個(gè)String存儲(chǔ)
protocolMethodPath=str.split(" ");//使用空格分割
if(protocolMethodPath.length==3)
{
requestMethod=protocolMethodPath[0];
requestPath=protocolMethodPath[1];
protocol=protocolMethodPath[2];
}
else
{
throw new Exception("首行參數(shù)不合適,請(qǐng)重新提交");
}
}
//獲得請(qǐng)求的協(xié)議
public String getProtocol()
{
return protocol;
}
//獲得請(qǐng)求的方法
public String getRequestMethod(){
return requestMethod;
}
//獲得請(qǐng)求的路徑
public String getRequestPath(){
return requestPath;
}
//獲得請(qǐng)求的消息報(bào)頭
public Map<String,String> getRequestHeader(){
return this.hmHeader;
}
//根據(jù)參數(shù)的名字獲得請(qǐng)求帶過來的參數(shù)值
public String getParameter(String parameterName){
return hmparameters.get(parameterName);
}
//判斷當(dāng)前請(qǐng)求的否是靜態(tài)資源
public boolean isStaticResource(){
return true;
}
//判斷當(dāng)前請(qǐng)求的否是動(dòng)態(tài)資源
public boolean isDynamicResource(){
return true;
}
//判斷當(dāng)前請(qǐng)求的否是為空請(qǐng)求(有些瀏覽器會(huì)自動(dòng)發(fā)送空請(qǐng)求)
public boolean isNullRequest(){
return isNullRequest;
}
}
以上內(nèi)容是對(duì)客戶端(瀏覽器)請(qǐng)求內(nèi)容的處理,即如何進(jìn)行包裝客戶端請(qǐng)求的信息,并且將其包裝成一個(gè)統(tǒng)一的整體,既然能夠獲取瀏覽器的內(nèi)容,那么,我們就必須采取一定的措施告訴瀏覽器我們找到了你想要的文件,并且將返回給客戶端,下面我們就來實(shí)現(xiàn)如何返回給客戶端想要的信息
二、response響應(yīng)處理
1、了解response響應(yīng)
服務(wù)器在接收和解釋客戶端的請(qǐng)求消息后,服務(wù)器會(huì)返回給客戶端一個(gè)HTTP響應(yīng)消息,我們稱之為響應(yīng)(response)。其實(shí)也是一個(gè)按照http協(xié)議的規(guī)則拼接而成的一個(gè)字符串
HTTP響應(yīng)也是由三個(gè)部分組成,分別是: 響應(yīng)狀態(tài)行、消息報(bào)頭、響應(yīng)正文
第一部分 響應(yīng)狀態(tài)行
格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
例如:
HTTP/1.1 200 OK
各部分分別為:
HTTP-Version表示服務(wù)器HTTP協(xié)議的版本;
Status-Code表示服務(wù)器發(fā)回的響應(yīng)狀態(tài)代碼;
Reason-Phrase表示狀態(tài)代碼的文本描述。
CRLF表示回車和換行
第二部分 消息報(bào)頭
HTTP消息報(bào)頭包括普通報(bào)頭、請(qǐng)求報(bào)頭、響應(yīng)報(bào)頭、實(shí)體報(bào)頭這四大類。
每一個(gè) 報(bào)頭域 都是由 名字+冒號(hào)+空格+值 組成,消息報(bào)頭域的名字不區(qū)分大小寫。它們的作用是描述 客戶端或者服務(wù)器 的屬性
1.普通報(bào)頭:即可用于請(qǐng)求,也可用于響應(yīng),是作為一個(gè)整體而不是特定資源與事務(wù)相關(guān)聯(lián)。
2.請(qǐng)求報(bào)頭:允許客戶端傳遞關(guān)于自身信息和希望的響應(yīng)形式。
3.響應(yīng)報(bào)頭:允許服務(wù)器傳遞關(guān)于自身信息的響應(yīng)。
4.實(shí)體報(bào)頭:定義被傳送資源的信息。即可用于請(qǐng)求,也可用于響應(yīng)。
什么是 MIME Type?
首先,我們要了解瀏覽器是如何處理內(nèi)容的。在瀏覽器中顯示的內(nèi)容有 HTML、有 XML、有 GIF、還有 Flash ……那么,瀏覽器是如何區(qū)分它們,決定什么內(nèi)容用什么形式來顯示呢?答案是 MIME Type,也就是該資源的媒體類型。媒體類型通常是通過 HTTP 協(xié)議,由 Web 服務(wù)器告知瀏覽器的,更準(zhǔn)確地說,是通過響應(yīng)的消息報(bào)頭里面的屬性 Content-Type 來表示的,例如:Content-Type: text/HTML表示內(nèi)容是 text/HTML 類型,也就是超文本文件。為什么是“text/HTML”而不是“HTML/text”或者別的什么?MIME Type 不是個(gè)人指定的,是經(jīng)過 ietf 組織協(xié)商,以 RFC 的形式作為建議的標(biāo)準(zhǔn)發(fā)布在網(wǎng)上的,大多數(shù)的 Web 服務(wù)器和用戶代理都會(huì)支持這個(gè)規(guī)范 (順便說一句,Email 附件的類型也是通過 MIME Type 指定的)。
通常只有一些在互聯(lián)網(wǎng)上獲得廣泛應(yīng)用的格式才會(huì)獲得一個(gè) MIME Type,如果是某個(gè)客戶端自己定義的格式,一般只能以 application/x- 開頭。XHTML 正是一個(gè)獲得廣泛應(yīng)用的格式,因此,在 RFC 3236 中,說明了 XHTML 格式文件的 MIME Type 應(yīng)該是 application/xHTML+XML。當(dāng)然,處理本地的文件,在沒有人告訴瀏覽器某個(gè)文件的 MIME Type 的情況下,瀏覽器也會(huì)做一些默認(rèn)的處理,這可能和你在操作系統(tǒng)中給文件配置的 MIME Type 有關(guān)。比如在 Windows 下,打開注冊(cè)表的“HKEY_LOCAL_MACHINESOFTWAREClassesMIMEDatabaseContent Type”主鍵,你可以看到所有 MIME Type 的配置信息
每個(gè)MIME類型由兩部分組成,前面是數(shù)據(jù)的大類別,例如聲音audio、圖象image等,后面定義具體的種類。
常見的MIME類型
超文本標(biāo)記語言文本 .html,.html text/html
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
GIF圖形 .gif image/gif
JPEG圖形 .ipeg,.jpg image/jpeg
au聲音文件 .au audio/basic
MIDI音樂文件 mid,.midi audio/midi,audio/x-midi
RealAudio音樂文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
第三部分 響應(yīng)正文
響應(yīng)正文就是服務(wù)器返回的資源的內(nèi)容
2、實(shí)現(xiàn)
首先,我們需要進(jìn)行抽象,即將瀏覽器想要的信息,即如下內(nèi)容包裝起來,如下所示,我們將其包裝成一個(gè)接口,在抽象時(shí)我們必須認(rèn)識(shí)到用戶可能會(huì)犯的錯(cuò)誤,所以盡量使用重載的方法進(jìn)行避免,在下面的接口中,使用了重載進(jìn)行處理部分方法:
package com.sample.http;
import java.io.OutputStream;
import java.io.PrintWriter;
//http協(xié)議的響應(yīng)
public interface HttpResponse {
//獲得一個(gè)指向客戶端的字節(jié)流
public OutputStream getOutputStream()throws Exception;
//獲得一個(gè)指向客戶端的字符流
public PrintWriter getPrintWriter()throws Exception;
//設(shè)置響應(yīng)的狀態(tài)行 參數(shù)為String類型
public void setStatusLine(String statusCode);
//設(shè)置響應(yīng)的狀態(tài)行 參數(shù)為int類型
public void setStatusLine(int statusCode);
//設(shè)置響應(yīng)消息報(bào)頭
public void setResponseHeader(String hName,String hValue);
//設(shè)置響應(yīng)消息報(bào)頭中Content-Type屬性
public void setContentType(String contentType);
//設(shè)置響應(yīng)消息報(bào)頭中Content-Type屬性 并且同時(shí)設(shè)置編碼
public void setContentType(String contentType,String charsetName);
//設(shè)置CRLF 回車換行 \r\n
public void setCRLF();
//把設(shè)置好的響應(yīng)狀態(tài)行、響應(yīng)消息報(bào)頭、固定空行這三部分寫給瀏覽器
public void printResponseHeader();
//把響應(yīng)正文寫給瀏覽器
public void printResponseContent(String requestPath);
}
在接口中,我們能夠看到詳細(xì)的解釋,下面我們就來實(shí)現(xiàn)接口中的方法:
package com.sample.http;
<pre name="code" class="java">import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import com.sample.utils.ConfigUtils;
import com.sample.utils.StatusCodeUtils;
//http協(xié)議的響應(yīng)
public class HttpResponseImpl implements HttpResponse {
//聲明初始變量
Socket s;//客戶端socket
OutputStream os;//輸出端字節(jié)流
BufferedWriter bw;//輸出端字符流
PrintWriter pw;
StringBuffer sbuffer;//放狀態(tài)行,\r\n ,
FileInputStream fis;
File file;
//構(gòu)造器
public HttpResponseImpl(Socket s) {
this.s=s;
System.out.println("HttpRequestImpl(Socket s)");
os=null;
bw=null;
pw=null;
sbuffer=new StringBuffer();//初始化,記得,否則以下的操作會(huì)遇見空指針異常
fis=null;
file=null;
getInfos();
}
private void getInfos() {
try {
os=s.getOutputStream();
bw=new BufferedWriter(new OutputStreamWriter(os,"GBK"));
pw=new PrintWriter(bw);
} catch (Exception e) {
e.printStackTrace();
}
}
//獲得一個(gè)指向客戶端的字節(jié)流
public OutputStream getOutputStream()throws Exception
{
return os;
}
//獲得一個(gè)指向客戶端的字符流
public PrintWriter getPrintWriter()throws Exception
{
return pw;
}
//設(shè)置響應(yīng)的狀態(tài)行 參數(shù)為String類型
public void setStatusLine(String statusCode)
{
String str=StatusCodeUtils.getStatusCodeValue(statusCode);
//System.out.println(str+"------"+str.length());
sbuffer.append("HTTP/1.1 "+statusCode+" "+str);
setCRLF();
}
//設(shè)置響應(yīng)的狀態(tài)行 參數(shù)為int類型
public void setStatusLine(int statusCode)
{
setStatusLine(statusCode+"");//將int類型轉(zhuǎn)化為String類型
}
//設(shè)置響應(yīng)消息報(bào)頭
public void setResponseHeader(String hName,String hValue)
{
sbuffer.append(hName+": "+hValue);
setCRLF();
}
//設(shè)置響應(yīng)消息報(bào)頭中Content-Type屬性
public void setContentType(String contentType)
{
setResponseHeader("Content-Type",contentType);
}
//設(shè)置響應(yīng)消息報(bào)頭中Content-Type屬性 并且同時(shí)設(shè)置編碼
public void setContentType(String contentType,String charsetName)
{//text/html;charset=utf-8
setContentType(";charset= "+charsetName);
}
//設(shè)置CRLF 回車換行 \r\n
public void setCRLF()
{
sbuffer.append("\r\n");
}
//把設(shè)置好的響應(yīng)狀態(tài)行、響應(yīng)消息報(bào)頭、固定空行這三部分寫給瀏覽器
public void printResponseHeader()
{
//設(shè)置setResponseLine,setResponseHeader,setResponseType
String res=sbuffer.toString();
pw.print(res);
pw.flush();
}
//把響應(yīng)正文寫給瀏覽器
public void printResponseContent(String requestPath)
{
//響應(yīng)正文
String getPath= requestPath;//客戶請(qǐng)求的地址
String webHome=(new ConfigUtils()).getConfigValue("rootPath");
System.out.println("配置文件中目錄:"+webHome);//輸出從配置文件中獲取的地址
file=new File(webHome+getPath);
if(file.exists())//如果文件存在就執(zhí)行
{
try {
fis=new FileInputStream(file);
byte[] buf=new byte[1024];
int len=-1;
while((len=fis.read(buf))!=-1)
{
//String str=buf.toString();
//bw.write(str);//字符流寫過去是一個(gè)地址,因?yàn)閷戇^去之后需要瀏覽器解析,如果是圖片或者其他(圖片或視頻是字節(jié)流)的該怎么解析呢?
//System.out.println(str);
os.write(buf, 0, len);
}
bw.flush();
os.flush();//os要不要關(guān)???
} catch (IOException e) {
e.printStackTrace();
}finally
{
try {
if(bw!=null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
在Eclipse中寫完以上代碼我們會(huì)發(fā)現(xiàn),其中有多處錯(cuò)誤信息,其原因是我們沒有進(jìn)行創(chuàng)建以上代碼所要求的類,現(xiàn)在我們進(jìn)行創(chuàng)建,其使用方法請(qǐng)參見:java.util 類 Properties ,使用參考中的方法,我們能夠進(jìn)行對(duì)所需要的信息進(jìn)行配置,在以上代碼中使用的地方有兩處,分別是【注意:這樣做的好處是增減了項(xiàng)目的靈活性,用戶能夠在不查看代碼的情況下隨時(shí)更改配置文件等一些文件的信息,】:
(1)設(shè)置狀態(tài)行處
//設(shè)置響應(yīng)的狀態(tài)行 參數(shù)為String類型
public void setStatusLine(String statusCode)
{
String str=StatusCodeUtils.getStatusCodeValue(statusCode);
//System.out.println(str+"------"+str.length());
sbuffer.append("HTTP/1.1 "+statusCode+" "+str);
setCRLF();
}
其中StatusCodeUtils類創(chuàng)建如下所示,而對(duì)于status_code.properties文件存放在下載的準(zhǔn)備文件中的/webservlet/project/中,直接復(fù)制到項(xiàng)目中即可:
package com.sample.utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class StatusCodeUtils {
private static Properties p;
static
{
InputStream in=null;
p=new Properties();
try {
//讀了xx.properties文件
in=StatusCodeUtils.class.getResourceAsStream("status_code.properties");
//放置到p中,即放properties文件中的key,value
p.load(in);
} catch (IOException e) {
e.printStackTrace();
}
finally
{
if(in!=null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String getStatusCodeValue(String status)
{
return p.getProperty(status);
}
public static String getStatusCodeValue(int status)
{
return getStatusCodeValue(status+"");//沒有空格
}
/*public static void main(String[] args) {//輸出測(cè)試
//Properties p=new Properties();
// p.setProperty("rootPath","ddd");
//System.out.println(p.get("rootPath"));
System.out.println(getStatusCodeValue("304"));
System.out.println(getStatusCodeValue("200"));
}*/
}
(2)響應(yīng)正文處:
//響應(yīng)正文
String getPath= requestPath;//客戶請(qǐng)求的地址
String webHome=(new ConfigUtils()).getConfigValue("rootPath");
System.out.println("配置文件中目錄:"+webHome);//輸出從配置文件中獲取的地址
file=new File(webHome+getPath);
在響應(yīng)正文中使用了ConfigUtils類進(jìn)行了項(xiàng)目路徑的獲取,代碼如下所示,對(duì)于config.properties(注意:此文件中文件路徑應(yīng)該注意,我使用的是Linux系統(tǒng),文件結(jié)構(gòu)是/home/***,而對(duì)于windows系統(tǒng),目錄結(jié)構(gòu)為:"C://webapps/*****,最好在地址欄復(fù)制地址,寫到配置中")文件也在準(zhǔn)備文件中,請(qǐng)自行下載,然后復(fù)制到項(xiàng)目中:就是下面這個(gè)東西,路徑配置合適,然后你就可以將自己的項(xiàng)目放在webapps目錄下,讓自己的電腦作為服務(wù)器供其他人訪問自己的網(wǎng)站了

ConfigUtils路徑配置類,用于獲取項(xiàng)目文件目錄位置
package com.sample.utils;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
public class ConfigUtils {
private static Properties p;
static
{
InputStream in=null;
OutputStream on=null;
p=new Properties();
try {
//讀了xx.properties文件
in=ConfigUtils.class.getResourceAsStream("config.properties");
//放置到p中,即放properties文件中的key,value
p.load(in);
} catch (IOException e) {
e.printStackTrace();
}
finally
{
if(in!=null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String getConfigValue(String config)
{
return p.getProperty(config);
}
public static void main(String[] args) {//輸出測(cè)試
// Properties p=new Properties();
// p.setProperty("rootPath","ddd");
// System.out.println(p.get("rootPath"));
System.out.println(getConfigValue("rootPath"));
}
}
到此為止,我們已經(jīng)實(shí)現(xiàn)了服務(wù)器的主要任務(wù),接受請(qǐng)求和處理請(qǐng)求,下面我們進(jìn)行測(cè)試:
寫一個(gè)測(cè)試類如下:
package com.sample.http;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class ServerTest {
public static void main(String[] args) {
//聲明變量
ServerSocket ss=null;
Socket s=null;
boolean flag=true;
try {
int port=10002;
System.out.println("Server Port:"+port);
ss=new ServerSocket(port);
//while(flag)
{
//接受客戶端發(fā)送過來的Socket
s=ss.accept();
HttpRequestImpl request=new HttpRequestImpl(s);
// 用于測(cè)試收到的信息
System.out.println("獲取的路徑:"+request.getRequestPath());
System.out.println("獲取的:"+request.getProtocol());
System.out.println("獲取的:"+request.getRequestMethod());
System.out.println(request.getParameter("name"));
System.out.println(request.getParameter("id"));
Map<String,String> m=request.getRequestHeader();
Set<Entry<String,String>> set=m.entrySet();
Iterator it=set.iterator();
while(it.hasNext())
{
Entry entry=(Entry<String, String> )it.next();
System.out.println(entry.getKey()+"----"+entry.getValue());
}
//寫響應(yīng)給瀏覽器
/*
* 封裝:
* */
//輸出流
HttpResponseImpl response=new HttpResponseImpl(s);
response.setStatusLine(200);
response.setContentType("text/html");
response.printResponseHeader();
response.setCRLF();
response.printResponseHeader();
response.printResponseContent(request.getRequestPath());
//用于輸出信息
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在瀏覽器中輸入地址回車:http://127.0.0.1:10002/test.html?id=1212&name=suguniang ,能夠看到瀏覽器解析后的界面,當(dāng)其他電腦訪問時(shí)(其他電腦指的是同一個(gè)域內(nèi)的),只要將127.0.0.1修改為本地的ip地址即可

此時(shí)控制臺(tái)上也輸出相應(yīng)的信息:

web服務(wù)器項(xiàng)目中靜態(tài)請(qǐng)求和動(dòng)態(tài)請(qǐng)求處理:http://www.dbjr.com.cn/article/191243.htm
到此這篇關(guān)于淺談web服務(wù)器項(xiàng)目中request請(qǐng)求和response的相關(guān)響應(yīng)處理的文章就介紹到這了,更多相關(guān)web服務(wù)器 request請(qǐng)求 response響應(yīng)處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java連接Mysql數(shù)據(jù)庫詳細(xì)代碼實(shí)例
這篇文章主要介紹了Java連接Mysql數(shù)據(jù)庫詳細(xì)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
idea中將單個(gè)java類導(dǎo)出為jar包文件的方法
這篇文章主要給大家介紹了關(guān)于idea中將單個(gè)java類導(dǎo)出為jar包文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09
java讀取文件:char的ASCII碼值=65279,顯示是一個(gè)空字符的解決
這篇文章主要介紹了java讀取文件:char的ASCII碼值=65279,顯示是一個(gè)空字符的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
java并發(fā)等待條件的實(shí)現(xiàn)原理詳解
這篇文章主要介紹了java并發(fā)等待條件的實(shí)現(xiàn)原理詳解,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-11-11
Java 重寫時(shí)應(yīng)當(dāng)遵守的 11 條規(guī)則
這篇文章主要介紹了Java 重寫時(shí)應(yīng)當(dāng)遵守的 11 條規(guī)則,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
java實(shí)現(xiàn)將漢語轉(zhuǎn)換為拼音功能
這篇文章主要介紹了java實(shí)現(xiàn)將漢語轉(zhuǎn)換為拼音功能,非常不錯(cuò),具有參考借鑒價(jià)值 ,需要的朋友可以參考下2017-05-05
詳解java動(dòng)態(tài)代理的2種實(shí)現(xiàn)方式
目前Java開發(fā)包中包含了對(duì)動(dòng)態(tài)代理的支持,但是其實(shí)現(xiàn)只支持對(duì)接口的的實(shí)現(xiàn)。這篇文章主要介紹了詳解java動(dòng)態(tài)代理的2種實(shí)現(xiàn)方式 ,有興趣的可以了解一下。2016-11-11
基于Java解決華為機(jī)試實(shí)現(xiàn)密碼截取?
這篇文章主要介紹了基于Java解決華為機(jī)試實(shí)現(xiàn)密碼截取,文章圍繞主題相關(guān)資料展開詳細(xì)內(nèi)容,具有一的參考價(jià)值,需要的小伙伴可以參考一下,希望對(duì)你有所幫助2022-02-02

