欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于Java實(shí)現(xiàn)HttpServer模擬前端接口調(diào)用

 更新時(shí)間:2023年04月14日 08:52:38   作者:CrazyDragon_King  
這篇文章主要介紹了關(guān)于Java實(shí)現(xiàn)Http?Server模擬前端接口調(diào)用,Http?協(xié)議是建立在?TCP?協(xié)議之上的協(xié)議,所以能用?TCP?來自己模擬一個(gè)簡單的?Http?Server?當(dāng)然是可以的,需要的朋友可以參考下

Java 實(shí)現(xiàn) Http Server,模擬前端接口調(diào)用

前言: 最近看到一個(gè)很有意思的東西,手寫簡單的 Http Server,而且只需要使用 Socket 編程就行了。當(dāng)然了,才學(xué)過計(jì)算機(jī)網(wǎng)絡(luò),所以知道 Http 協(xié)議是建立在 TCP 協(xié)議之上的協(xié)議,所以能用 TCP 來自己模擬一個(gè)簡單的 Http Server 當(dāng)然是可以的。所以,自己實(shí)現(xiàn)了一個(gè)簡單的可以進(jìn)行 請(qǐng)求、響應(yīng) 的 Http Server,但是 Http 報(bào)文解析本身還是比較復(fù)雜的,所以只能處理簡單的情況。對(duì)于涉及二進(jìn)制數(shù)據(jù)的報(bào)文解析,還是一頭霧水。不過,這也沒關(guān)系,只是現(xiàn)在做不到而已。 因?yàn)槲铱梢耘袛嗲岸说恼?qǐng)求是什么,所以我也就能根據(jù)特定的請(qǐng)求去響應(yīng)特定的數(shù)據(jù)給前端,這個(gè)就和那個(gè)前端模擬接口調(diào)用有點(diǎn)相似了。(當(dāng)然了,都是一些簡單的數(shù)據(jù),哈哈?。┧裕妥隽诉@個(gè)小工具,它可以根據(jù)用戶的請(qǐng)求執(zhí)行特定的響應(yīng)數(shù)據(jù)。(而且不需要使用網(wǎng)絡(luò)了,只需要在本地就可以使用,并且我覺得對(duì)于簡單的情況,使用還是挺方便的。)

執(zhí)行結(jié)果展示

這里是兩個(gè)簡單的測試展示,最后有更多的測試示例。

訪問根目錄,然后會(huì)返回一句話(字符串)(注意:那條綠色的龍,只有使用瀏覽器訪問才能看到的,圖片本身也是屬于一個(gè)請(qǐng)求的。) Content-Type: application/json

在這里插入圖片描述

單獨(dú)訪問這張圖片,返回值是圖片(二進(jìn)制數(shù)據(jù))

在這里插入圖片描述

請(qǐng)求和響應(yīng)配置文件

所以只要用戶提前設(shè)置好請(qǐng)求信息和響應(yīng)信息,在訪問特定請(qǐng)求時(shí),就能返回特定數(shù)據(jù)。所以,我設(shè)計(jì)了一個(gè)簡單的 xml 文件用來配置這些信息,使用 xml 配置比較方便,properties 配置文件無法表達(dá)層次信息,只能適用于簡單的配置要求。

一個(gè)大的 request_and_responses 代表許多個(gè)請(qǐng)求和響應(yīng)配置,每一個(gè) request_and_response 節(jié)點(diǎn)代表一個(gè)request 請(qǐng)求和 response 響應(yīng)信息,里面包含了請(qǐng)求和響應(yīng)的基本信息。GET 方式請(qǐng)求主要包括:(method) 請(qǐng)求方法 和 (path) 請(qǐng)求路徑和參數(shù)。 POST 方法請(qǐng)求還包括一個(gè) (param )請(qǐng)求參數(shù)。 response 包括:content_type(響應(yīng)內(nèi)容類型) 和 value(響應(yīng)內(nèi)容)。

GET 和 POST 方式的區(qū)別在于,GET 方式的請(qǐng)求路徑和請(qǐng)求參數(shù)是在一起的(都在請(qǐng)求頭中,沒有請(qǐng)求體),而 POST 方式的請(qǐng)求參數(shù)則是在請(qǐng)求體里面的,請(qǐng)求頭和請(qǐng)求體之間有一個(gè) CRLF 分隔。

xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<request_and_responses>
	<!-- & 需要使用轉(zhuǎn)義字符 &amp; -->
		
	<request_and_response>
		<request>
			<method>GET</method>
			<path>/</path>
		</request>
		<response>
			<content_type>application/json</content_type>
			<value>I love you yesterday and today!</value>
		</response>
	</request_and_response>
	
	<request_and_response>
		<request>
			<method>GET</method>
			<path>/login?account=123&amp;pwd=456</path>
		</request>
		
		<response>
			<content_type>application/json</content_type>
			<value>success</value>
		</response>
	</request_and_response>
	
	<request_and_response>
		<request>
			<method>GET</method>
			<path>/query/龍</path>
		</request>
		<response>
			<content_type>application/json</content_type>
			<value>龍是中國等東亞國家古代神話傳說生活于海中的神異生物。</value>
		</response>
	</request_and_response>
	
	<request_and_response>
		<request>
			<method>POST</method>
			<path>/login</path>
			<param>account=123&amp;pwd=456</param>
		</request>
		
		<response>
			<content_type>application/json</content_type>
			<value>{"result":success}</value>
		</response>
	</request_and_response>
	
	
	<request_and_response>
		<request>
			<method>POST</method>
			<path>/login</path>
			<param>workId=12345</param>
		</request>
		
		<response>
			<content_type>application/json</content_type>
			<value>{"result":"success", "data":{"name":"李工", "sex":"男", "age":35}}</value>
		</response> 
	</request_and_response>
	
	
	<request_and_response>
		<request>
			<method>GET</method>
			<path>/pictures/husky.jpeg</path>
		</request>
		
		<response>
			<content_type>image/jpeg</content_type>
			<value>D:/DB/husky.jpeg</value>
		</response> 
	</request_and_response>
	
	<!-- 瀏覽器訪問時(shí)的圖標(biāo) -->
	<request_and_response>
		<request>
			<method>GET</method>
			<path>/favicon.ico</path>
		</request>
		
		<response>
			<content_type>image/webp</content_type>
			<value>D:/DB/favicon.ico</value>
		</response> 
	</request_and_response>
	
</request_and_responses>

xml 映射的實(shí)體類

xml 中的信息,讀取到內(nèi)存中,使用一個(gè)實(shí)體類來對(duì)信息進(jìn)行封裝。

package com.dragon;

public class RequestAndResponse {
	private String method;
	private String path;
	private String param;
	private String content_type;
	private String value;
	
	public String getMethod() {
		return method;
	}
	public void setMethod(String method) {
		this.method = method;
	}
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public String getParam() {
		return param;
	}
	public void setParam(String param) {
		this.param = param;
	}
	public String getContent_type() {
		return content_type;
	}
	public void setContent_type(String content_type) {
		this.content_type = content_type;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	
	@Override
	public String toString() {
		return "RequestAndResponse [method=" + method + ", path=" + path + ", param=" + param + ", content_type="
				+ content_type + ", value=" + value + "]";
	}
}

xml 文件解析器類

使用一個(gè)類專門解析 xml 文件為Java 對(duì)象,然后使用一個(gè) List 集合來存儲(chǔ)所有的對(duì)象。

注:不太會(huì)取名字,有點(diǎn)太長了,湊合著看吧!哈哈。 注:這里使用一個(gè)xml解析的jar包:dom4j。

package com.dragon;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 解析 xml 文件中配置的用戶請(qǐng)求和響應(yīng)數(shù)據(jù)。
 * */
public class RequestAndResponseResolver {
	private static final String method = "method";
	private static final String path = "path";
	private static final String param = "param";
	private static final String content_type = "content_type";
	private static final String value = "value";
	
	public static List<RequestAndResponse> listRequestAndResponse(String filePath) throws DocumentException{
		File file = new File(filePath); 
		SAXReader reader = new SAXReader();
		Document doc = reader.read(file);
		
		Element root = doc.getRootElement();
		//獲取根元素下面所有的子元素,利用迭代器方式
		Iterator<?> it = root.elementIterator();
		
		List<RequestAndResponse> requestAndResponses = new ArrayList<>();
		while (it.hasNext()) {
			//取出元素request_and_response
			Element e = (Element)it.next();
			//依次遍歷每一個(gè) request_and_response,獲取相應(yīng)的信息
			Element request = e.element("request");
			Element response = e.element("response");
			
			RequestAndResponse requestAndResponse = new RequestAndResponse();
			requestAndResponse.setMethod(request.elementText(method));
			requestAndResponse.setPath(request.elementText(path));
			requestAndResponse.setParam(request.elementText(param));   //GET 方式,這個(gè)屬性為 null
			requestAndResponse.setContent_type(response.elementText(content_type));
			requestAndResponse.setValue(response.elementText(value));
			
			requestAndResponses.add(requestAndResponse);
		}
		
		return requestAndResponses;
	}
}

接收請(qǐng)求并處理的部分

下面介紹一下,使用 Socket 接收并處理請(qǐng)求的部分。 這里涉及的知識(shí)和使用 Socket 基本上都是一樣的,唯一的區(qū)別就是對(duì)于內(nèi)容本身的處理,因?yàn)閮?nèi)容本身是包含數(shù)據(jù)和非數(shù)據(jù)部分的。(站在 HTTP 的角度,只能看到數(shù)據(jù)部分。) 使用 Socket 編程,簡單來說就是監(jiān)聽一個(gè)端口,一旦有連接到來,就進(jìn)行處理。(這里使用傳統(tǒng)的 BIO,NIO 那部分我不會(huì)。)

這里我的處理是,使用一個(gè)線程池進(jìn)行處理,每一個(gè)連接使用一個(gè)線程進(jìn)行處理。關(guān)于這個(gè)類(Server 類)的完整代碼,見下面。

	public void receive() {
		//使用線程池處理請(qǐng)求
		ExecutorService pool = Executors.newFixedThreadPool(THREAD_NUMBER);
		
		while (true) {
			try {
				Socket connection = server.accept();
				pool.submit(new UserConnection(connection));
			} catch (IOException e) {
				System.out.println(this.getDate()+" 用戶連接斷開");
				e.printStackTrace();
			}
		}
	}

接收請(qǐng)求的代碼:Server 類

package com.dragon;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
	private static final int THREAD_NUMBER = 10;
	private ServerSocket server;
	private int port;
	
	public Server(int port) {
		this.port = port;
	}
	
	//啟動(dòng)服務(wù)。
	public void start() {
		try {
			server = new ServerSocket(port);
			System.out.println(this.getDate()+" 服務(wù)啟動(dòng)!");
			this.receive();
		} catch (IOException e) {
			System.out.println(this.getDate()+" 服務(wù)啟動(dòng)失敗!");
			e.printStackTrace();
		}
	}
	
	public void receive() {
		//使用線程池處理請(qǐng)求
		ExecutorService pool = Executors.newFixedThreadPool(THREAD_NUMBER);
		
		while (true) {
			try {
				Socket connection = server.accept();
				pool.submit(new UserConnection(connection));
			} catch (IOException e) {
				System.out.println(this.getDate()+" 用戶連接斷開");
				e.printStackTrace();
			}
		}
	}
	
	
	
	private String getDate() {
		String format = "yyyy-MM-dd HH:mm:ss";
		Date now = new Date();
		SimpleDateFormat dateFormat = new SimpleDateFormat(format);
		return dateFormat.format(now);
	}
}

Http 請(qǐng)求報(bào)文從 TCP 的層次來看就是一段二進(jìn)制數(shù)據(jù)流(網(wǎng)絡(luò)是分層的),所以我們可以直接使用 TCP 接收這個(gè)流, 因?yàn)樯婕岸M(jìn)制數(shù)據(jù)(如文件上傳)的報(bào)文解析比較復(fù)雜,我也不知道該怎么做,所以這里我只是測試簡單的不含有二進(jìn)制文件的請(qǐng)求。)

注:因?yàn)榫唧w的解析也是很復(fù)雜的,這涉及到 HTTP 報(bào)文的結(jié)構(gòu),但是如果不涉及文件上傳,那么整個(gè)報(bào)文都是一些字符數(shù)據(jù),所以一次性讀取全部請(qǐng)求報(bào)文,然后轉(zhuǎn)成字符串,使用字符串來進(jìn)行解析。

in = connection.getInputStream();
out = connection.getOutputStream();
			
//這個(gè)數(shù)字是隨便設(shè)置的,因?yàn)橐淮涡宰x取整個(gè)請(qǐng)求報(bào)文,不能太小。(但是其實(shí)這個(gè)也很大了)
byte[] b = new byte[5*1024];
BufferedInputStream input = new BufferedInputStream(in);
int count = input.read(b);
String requestMessage = new String(b, 0, count);
System.out.println("====================報(bào)文分隔符上界===================");
System.out.println(requestMessage);
System.out.println("====================報(bào)文分隔符下界===================");

處理請(qǐng)求代碼:UserConnection 類

請(qǐng)求和響應(yīng)信息初始化 說明:使用靜態(tài)初始化塊來初始化信息,將用戶提前配置好的 xml 信息讀取入內(nèi)存,前面提到過這部分。

// 初始化配置好的信息
	static {
		try {
			requestAndResponses = RequestAndResponseResolver.listRequestAndResponse("./src/com/dragon/request_and_response.xml");
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

請(qǐng)求處理和獲取響應(yīng)信息 因?yàn)檫@里是模擬調(diào)用,所以我主要關(guān)注請(qǐng)求頭中的三個(gè)部分?jǐn)?shù)據(jù):請(qǐng)求方法(method)、請(qǐng)求路徑(path)、請(qǐng)求參數(shù)(param)。 對(duì)于 GET 方式和 POST 方式分開進(jìn)行處理,上面簡單介紹了 GET 和 POST 的區(qū)別(但是不夠詳細(xì),可以去參考網(wǎng)上的其它資料了解)。

通過這段代碼,如果是 GET 方式,就將 RequestAndResponse 對(duì)象中的 content_type(返回值數(shù)據(jù)類型) 和 value (返回值數(shù)據(jù))取出來,并賦值給局部變量 content_type 和 value。

if ("GET".compareTo(method) == 0) {
	for (RequestAndResponse r : requestAndResponses) {
		//這里需要對(duì) get 方式時(shí)的請(qǐng)求進(jìn)行解碼,因?yàn)橐恍┓?ASCII 碼字符會(huì)被編碼,比如漢字。
		path = URLDecoder.decode(path, ENCODE);
		if (r.getMethod().equals(method) && r.getPath().equals(path)) {
			content_type = r.getContent_type();
			value = r.getValue();
			break;
		}
	}
} else {
	//POST 方式,請(qǐng)求參數(shù)是在請(qǐng)求體中的,請(qǐng)求頭和請(qǐng)求體中間有一個(gè)換行符。
	String param = requestMessage.substring(requestMessage.lastIndexOf(CRLF) + 2); //這里是不包括 CRLF 的兩個(gè)字符的。
	for (RequestAndResponse r : requestAndResponses) {                 //因?yàn)檫@個(gè)get方式的 參數(shù)為空,所以這里必須是 param 在前。
		if (r.getMethod().equals(method) && r.getPath().equals(path) && param.equals(r.getParam())) {
			content_type = r.getContent_type();
			value = r.getValue();
			break;
		}
	}
}

這里介紹一個(gè)知識(shí):URL 中的字符是特定的,不允許中文等字符的出現(xiàn),所以發(fā)送請(qǐng)求時(shí)會(huì)對(duì)中文等字符進(jìn)行編碼,如果直接使用 equals 方法的,當(dāng)然不會(huì)相等了,所以需要先對(duì)數(shù)據(jù)進(jìn)行解碼,然后再調(diào)用 equals 方法進(jìn)行處理。這個(gè)是我們平時(shí)廣泛使用 的東西,有時(shí)候使用瀏覽器可以看到帶很多奇怪字符 URL,它們都是被處理過的。

舉一個(gè)簡單的例子:

String str = "我愛你";
String en_str = java.net.URLEncoder.encode(str, "UTF-8");
String de_str = java.net.URLDecoder.decode(en_str, "UTF-8");
System.out.println("編碼字符:" + en_str);
System.out.println("解碼字符:" + de_str);

在這里插入圖片描述

注意:這里有一個(gè)特殊的情況,如果發(fā)起了沒有配置的請(qǐng)求方法和路徑,那么程序會(huì)出錯(cuò)。所以,這里的 content_type 和 value 有一個(gè)默認(rèn)的值,而且非常有趣!

在這里插入圖片描述

執(zhí)行響應(yīng) 響應(yīng)信息主要關(guān)注幾點(diǎn):響應(yīng)信息長度(Content-Length)(按字節(jié)數(shù)計(jì)算)、響應(yīng)內(nèi)容類型(Content-Type)。

雖然發(fā)送的請(qǐng)求里不能帶二進(jìn)制文件,但是響應(yīng)信息是可以返回文件的,而且使用 Content-Length (一次性發(fā)送),不使用 Chunked 分塊發(fā)送(這里我還不太明白,而且只是模擬,應(yīng)該使用一些簡單的小文件。)。

下面是區(qū)分響應(yīng)類型為 json (字符串) 還是 文件(二進(jìn)制數(shù)據(jù)) 的代碼:

如果是字符串,則 value 的值是字符串的值,如果是文件,則 value 的值為一個(gè)具體的本地路徑。(不應(yīng)該使用網(wǎng)絡(luò)圖片,即使修改程序可以做到也沒有必要,因?yàn)檫@樣就需要依賴網(wǎng)絡(luò)了。)

	//這里我只處理字符串類和文件類兩種響應(yīng)體
	//響應(yīng)體
	int len = 0;
	String responseBody = null;   //響應(yīng)值是 json 數(shù)據(jù)
	File file = null; //響應(yīng)值是 文件
	if (content_type.equals("application/json")) {  //如果是 json 數(shù)據(jù),否則就是 文件類數(shù)據(jù)(圖片、文檔或其它文件)
		 responseBody = value;
		 len = responseBody.getBytes().length;   //響應(yīng)體的字節(jié)數(shù),注意是字節(jié)數(shù)!
	} else {
		 file = new File(value);
		 len = (int) file.length();
	}

然后就可以準(zhǔn)備發(fā)送響應(yīng)數(shù)據(jù)了,下面是發(fā)送響應(yīng)的代碼,注意報(bào)文的具體結(jié)構(gòu)。

	//響應(yīng)頭
	responseHeader.append("HTTP/1.1").append(BLANK);
	responseHeader.append(200).append(BLANK);
	responseHeader.append("OK").append(CRLF);
	responseHeader.append("Server:"+"CrazyDragon").append(CRLF);
	responseHeader.append("Date:").append(BLANK).append(date).append(CRLF);
	responseHeader.append("Content-Type:").append(BLANK).append(content_type).append(CRLF);
	responseHeader.append("Content-Length:").append(BLANK).append(len).append(CRLF);
	responseHeader.append(CRLF);
	
	//如果 字符串變量 responseBody 不為空,則說明返回值是 json 數(shù)據(jù)(字符串)
	//否則就是文件類的流了。
	if (responseBody != null) {
		String response = responseHeader.toString() + responseBody;
		out.write(response.getBytes("UTF-8"));    
	} else {
		out.write(responseHeader.toString().getBytes("UTF-8"));  
		
		int hasRead = 0;
		byte[] data = new byte[4*1024];
		try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
			while ((hasRead = inputStream.read(data)) != -1) {
				out.write(data, 0, hasRead);
			}
		}
	}
	out.flush();   //必要的刷新流操作。

User Connection 的完整代碼:

package com.dragon;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import org.dom4j.DocumentException;

public class UserConnection implements Runnable{
	private static final String BLANK = " ";
	private static final String CRLF = "\r\n"; //換行符,不能寫反了!
	private static final String ENCODE = "UTF-8";
	private static final String default_content_type = "application/json";   //當(dāng)任何匹配路徑都沒有時(shí)。
	private static final String default_value = "404 NOT FOUND!\n沒有找到你配置的請(qǐng)求!";
	
	
	private static List<RequestAndResponse> requestAndResponses;
	private Socket connection;
	
	
	// 初始化配置好的信息
	static {
		try {
			requestAndResponses = RequestAndResponseResolver.listRequestAndResponse("./src/com/dragon/request_and_response.xml");
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}
	
	
	
	public UserConnection(Socket connection) {
		this.connection = connection;
	}
	
	@Override
	public void run() {
		InputStream in = null;
		OutputStream out = null;
		try {
			in = connection.getInputStream();
			out = connection.getOutputStream();
			
			//這個(gè)數(shù)字是隨便設(shè)置的,因?yàn)橐淮涡宰x取整個(gè)請(qǐng)求報(bào)文,不能太小。(但是其實(shí)這個(gè)也很大了)
			byte[] b = new byte[5*1024];
			BufferedInputStream input = new BufferedInputStream(in);
			int count = input.read(b);
			String requestMessage = new String(b, 0, count);
			System.out.println("====================報(bào)文分隔符上界===================");
			System.out.println(requestMessage);
			System.out.println("====================報(bào)文分隔符下界===================");

			//以第一個(gè) 換行符 CRLF 為界限取出 請(qǐng)求路徑和請(qǐng)求參數(shù)
			String requestLine = requestMessage.substring(0, requestMessage.indexOf(CRLF));
			String[] line = requestLine.split("\\s");
			String method = line[0];  //考慮大小寫。
			String path = line[1];  
			//這個(gè)數(shù)組是有三個(gè)元素,最后一個(gè)是 協(xié)議的版本,這里不需要,就不處理了。
			String content_type = default_content_type;
			String value = default_value;
			if ("GET".compareTo(method) == 0) {
			//	System.out.println("請(qǐng)求方式:" + method + " 請(qǐng)求路徑(含參數(shù)):" + path);
				for (RequestAndResponse r : requestAndResponses) {
					//這里需要對(duì) get 方式時(shí)的請(qǐng)求進(jìn)行解碼,因?yàn)橐恍┓?ASCII 碼字符會(huì)被編碼,比如漢字。
					path = URLDecoder.decode(path, ENCODE);
					if (r.getMethod().equals(method) && r.getPath().equals(path)) {
						content_type = r.getContent_type();
						value = r.getValue();
						break;
					}
				}
			} else {
				//POST 方式,請(qǐng)求參數(shù)是在請(qǐng)求體中的,請(qǐng)求頭和請(qǐng)求體中間有一個(gè)換行符。
				String param = requestMessage.substring(requestMessage.lastIndexOf(CRLF) + 2); //這里是不包括 CRLF 的兩個(gè)字符的。
				for (RequestAndResponse r : requestAndResponses) {                 //因?yàn)檫@個(gè)get方式的 參數(shù)為空,所以這里必須是 param 在前。
					if (r.getMethod().equals(method) && r.getPath().equals(path) && param.equals(r.getParam())) {
						content_type = r.getContent_type();
						value = r.getValue();
						System.out.println(content_type+" "+value);
						break;
					}
				}
			}
		
			StringBuilder responseHeader = new StringBuilder();
			String date = this.getDate();
			
			
			//這里我只處理字符串類和文件類兩種響應(yīng)體
			//響應(yīng)體
			int len = 0;
			String responseBody = null;   //響應(yīng)值是 json 數(shù)據(jù)
			File file = null; //響應(yīng)值是 文件
			if (content_type.equals("application/json")) {  //如果是 json 數(shù)據(jù),否則就是 文件類數(shù)據(jù)(圖片、文檔或其它文件)
				 responseBody = value;
				 len = responseBody.getBytes().length;   //響應(yīng)體的字節(jié)數(shù),注意是字節(jié)數(shù)!
			} else {
				 file = new File(value);
				 len = (int) file.length();
			}
			
			//響應(yīng)頭
			responseHeader.append("HTTP/1.1").append(BLANK);
			responseHeader.append(200).append(BLANK);
			responseHeader.append("OK").append(CRLF);
			responseHeader.append("Server:"+"CrazyDragon").append(CRLF);
			responseHeader.append("Date:").append(BLANK).append(date).append(CRLF);
			responseHeader.append("Content-Type:").append(BLANK).append(content_type).append(CRLF);
			responseHeader.append("Content-Length:").append(BLANK).append(len).append(CRLF);
			responseHeader.append(CRLF);
			
			//如果 字符串變量 responseBody 不為空,則說明返回值是 json 數(shù)據(jù)(字符串)
			//否則就是文件類的流了。
			if (responseBody != null) {
				String response = responseHeader.toString() + responseBody;
				out.write(response.getBytes("UTF-8"));    
			} else {
				out.write(responseHeader.toString().getBytes("UTF-8"));  
				
				int hasRead = 0;
				byte[] data = new byte[4*1024];
				try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
					while ((hasRead = inputStream.read(data)) != -1) {
						out.write(data, 0, hasRead);
					}
				}
			}
			out.flush();   //必要的刷新流操作。
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null)
					in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private String getDate() {
		Date date = new Date();
		SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.CHINA);
		format.setTimeZone(TimeZone.getTimeZone("GMT")); // 設(shè)置時(shí)區(qū)為GMT  
		return format.format(date);
	}
}

主程序類:Main

package com.dragon;

public class Main {
	public static void main(String[] args) {
		Server server = new Server(9000);
		server.start();		
	}
}

更多的測試示例

請(qǐng)求方式:GET 請(qǐng)求路徑和參數(shù):/query/龍 預(yù)期的響應(yīng)類型:application/json 預(yù)期的響應(yīng)值:龍是中國等東亞國家古代神話傳說生活于海中的神異生物。 測試結(jié)果:

在這里插入圖片描述

請(qǐng)求方式:GET 請(qǐng)求路徑和參數(shù):/login?account=123&pwd=456 預(yù)期的響應(yīng)類型:application/json 預(yù)期的響應(yīng)值:success 測試結(jié)果:

在這里插入圖片描述

請(qǐng)求方式:GET 請(qǐng)求路徑和參數(shù):/pictures/husky.jpeg 預(yù)期的響應(yīng)類型:image/jpeg 預(yù)期的響應(yīng)值:一張圖片(地址為:D:/DB/husky.jpeg) 測試結(jié)果:

在這里插入圖片描述

請(qǐng)求方式:POST 請(qǐng)求路徑:/login 請(qǐng)求參數(shù):account=123&pwd=456 預(yù)期的響應(yīng)類型:application/json 預(yù)期的響應(yīng)值:{“result”:success} 測試結(jié)果:

在這里插入圖片描述

注:這是使用 HttpClient 發(fā)送的 POST 請(qǐng)求。

在這里插入圖片描述

接收到的 POST 請(qǐng)求:

在這里插入圖片描述

接收到的 GET 請(qǐng)求(含中文參數(shù)): /query/龍 注意:“龍” 已經(jīng)被編碼了。

在這里插入圖片描述

總結(jié)

最近抽了一點(diǎn)時(shí)間,寫這個(gè)小玩具(也許并沒有什么用吧),中間也思考了很多東西,發(fā)現(xiàn)這個(gè)關(guān)于協(xié)議這個(gè)東西還是挺有趣的,不過我的知識(shí)似乎也不夠了。對(duì)于報(bào)文解析這種事情,沒有一定的基礎(chǔ)知識(shí)是做不來的,特別是復(fù)雜的報(bào)文(Content-Type 為 multipart/form-data)。這些以后有機(jī)會(huì)再去嘗試吧,就先到這里了。

到此這篇關(guān)于關(guān)于Java實(shí)現(xiàn)HttpServer模擬前端接口調(diào)用的文章就介紹到這了,更多相關(guān)HttpServer模擬前端接口調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM的垃圾回收算法一起來看看

    JVM的垃圾回收算法一起來看看

    這篇文章主要為大家詳細(xì)介紹了JVM的垃圾回收算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • Spring?Boot?詳細(xì)分析Conditional自動(dòng)化配置注解

    Spring?Boot?詳細(xì)分析Conditional自動(dòng)化配置注解

    首先我們先了解一下@Conditional注解,@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,需要注入的Bean滿足給定條件才可以注入到Spring?IOC容器中
    2022-07-07
  • Jmeter對(duì)響應(yīng)數(shù)據(jù)實(shí)現(xiàn)斷言代碼實(shí)例

    Jmeter對(duì)響應(yīng)數(shù)據(jù)實(shí)現(xiàn)斷言代碼實(shí)例

    這篇文章主要介紹了Jmeter對(duì)響應(yīng)數(shù)據(jù)實(shí)現(xiàn)斷言代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 詳談鎖和監(jiān)視器之間的區(qū)別_Java并發(fā)

    詳談鎖和監(jiān)視器之間的區(qū)別_Java并發(fā)

    下面小編就為大家?guī)硪黄斦勬i和監(jiān)視器之間的區(qū)別_Java并發(fā)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • 一文搞懂hashCode()和equals()方法的原理

    一文搞懂hashCode()和equals()方法的原理

    這篇文章主要介紹了詳解hashCode()和equals()的本質(zhì)區(qū)別和聯(lián)系,本文先對(duì)兩種方法作了介紹,然后對(duì)二者聯(lián)系進(jìn)行分析,具有一定參考價(jià)值,需要的朋友可以了解下
    2020-06-06
  • Spring Boot接口限流的常用算法及特點(diǎn)

    Spring Boot接口限流的常用算法及特點(diǎn)

    這篇文章主要給大家介紹了關(guān)于Spring Boot接口限流的常用算法及特點(diǎn)的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 詳解Spring boot/Spring 統(tǒng)一錯(cuò)誤處理方案的使用

    詳解Spring boot/Spring 統(tǒng)一錯(cuò)誤處理方案的使用

    這篇文章主要介紹了詳解Spring boot/Spring 統(tǒng)一錯(cuò)誤處理方案的使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • java實(shí)現(xiàn)快速排序圖文詳解

    java實(shí)現(xiàn)快速排序圖文詳解

    網(wǎng)上關(guān)于快速排序的算法原理和算法實(shí)現(xiàn)都比較多,不過java是實(shí)現(xiàn)并不多,而且部分實(shí)現(xiàn)很難理解,和思路有點(diǎn)不搭調(diào)。所以整理了這篇文章。如果有不妥之處還請(qǐng)建議
    2021-08-08
  • spring集成okhttp3的步驟詳解

    spring集成okhttp3的步驟詳解

    okhttp是一個(gè)封裝URL,比HttpClient更友好易用的工具,下面這篇文章主要給大家介紹了關(guān)于spring集成okhttp3的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2018-04-04
  • SpringBoot自定義錯(cuò)誤處理邏輯詳解

    SpringBoot自定義錯(cuò)誤處理邏輯詳解

    這篇文章主要介紹了SpringBoot自定義錯(cuò)誤處理邏輯,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-10-10

最新評(píng)論