淺談web服務器項目中request請求和response的相關(guān)響應處理
我們經(jīng)常使用別人的服務器進行構(gòu)建網(wǎng)站,現(xiàn)在我們就自己來寫一個自己的服務來使用。
準備工作:下載所需的題材及文檔
注:完整項目下載
一、request請求獲取
1、了解request請求
在寫服務器之前,我們需要知道客戶端發(fā)送給我們哪些信息?以及要求我們返回哪些信息?經(jīng)過測試我們能夠知道用戶客戶端發(fā)送的信息有以下幾點:
客戶端發(fā)送到服務器端的請求消息,我們稱之為請求(request),其實就是一個按照http協(xié)議的規(guī)則拼接而成的字符串,Request請求消息包含三部分: 請求行 消息報頭 請求正文
第一部 請求行
格式:
Method Request-URI HTTP-Version CRLF
各部分分別為:
Method表示請求方法;一般為GET或者POST ;Request-URI是一個統(tǒng)一資源標識符; HTTP-Version表示請求的HTTP協(xié)議版本; CRLF表示回車和換行
例如:
GET /test.html HTTP/1.1
第二部 消息報頭 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
第三部 請求正文 http body
請求頭和請求正文之間是一個空行,這個行非常重要,它表示請求頭已經(jīng)結(jié)束,接下來的是請求正文。請求正文中可以包含客戶提交的字符串信息
注意:在第二部分header和第三部分body之間有個空行,除非沒有請求正文(如果你想要親自看到效果,請參考:瀏覽器中GET和POST的區(qū)別),這是因為用戶在瀏覽網(wǎng)頁時提交給服務器的信息是不同的
2、實現(xiàn)
經(jīng)過以上分析,我們就能夠清楚的知道,客戶端發(fā)送給服務器的請求,請求信息有使用的協(xié)議、請求的方法、請求的資源路徑、請求的消息報頭、判斷請求的內(nèi)容是否為靜態(tài)資源、判斷請求的內(nèi)容是否為動態(tài)資源、判斷是否為空請求,為了使用的方便,我們需要將其封裝起來,總不能使用一次讀取一次吧,這樣做實在是太浪費系統(tǒng)資源與時間了,如下代碼,就是一個接口類,用于獲取客戶端發(fā)送過來的屬性
package com.sample.http;
import java.util.Map;
// http協(xié)議的請求
public interface HttpRequest {
//獲得請求的協(xié)議
public String getProtocol();
//獲得請求的方法
public String getRequestMethod();
//獲得請求的路徑
public String getRequestPath();
//獲得請求的消息報頭
public Map<String,String> getRequestHeader();
//根據(jù)參數(shù)的名字獲得請求帶過來的參數(shù)值
public String getParameter(String parameterName);
//判斷當前請求的否是靜態(tài)資源
public boolean isStaticResource();
//判斷當前請求的否是動態(tài)資源
public boolean isDynamicResource();
//判斷當前請求的否是為空請求(有些瀏覽器會自動發(fā)送空請求)
public boolean isNullRequest();
}
有了接口類之后,我們就可以創(chuàng)建類進行實現(xiàn),下面就是實現(xià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>();//消息報頭
private HashMap<String,String> hmparameters=new HashMap<String, String>();//參數(shù)集合
private boolean isNullRequest=false;//是否為空請求,默認false
private String protocol=null;//請求協(xié)議
private String requestMethod=null;//請求方法
private String requestPath=null;//請求路徑
public HttpRequestImpl(Socket s) {
this.s=s;
getInfos();//調(diào)用方法
}
private void getInfos()//定義一個方法,用于處理獲取的客戶端信息
{
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é)束就退出,這里的判斷按較為饒人
//首先應該明確br.readLine()的內(nèi)容,當為true是對應的情況
//也就是說當“”(中間沒有空格)與br.readLine()相等時,就進入到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é)進行讀取,因為這一行沒有回車換行,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("消息報頭異常,請重新提交");
}
hmHeader.put(headHost[0],headHost[1]);
}
//解析第一行
private void parseRequestMethodPathProtocol(String str) throws Exception {
String[] protocolMethodPath=new String[3];//由于第一行含有三個內(nèi)容,分割后需要三個String存儲
protocolMethodPath=str.split(" ");//使用空格分割
if(protocolMethodPath.length==3)
{
requestMethod=protocolMethodPath[0];
requestPath=protocolMethodPath[1];
protocol=protocolMethodPath[2];
}
else
{
throw new Exception("首行參數(shù)不合適,請重新提交");
}
}
//獲得請求的協(xié)議
public String getProtocol()
{
return protocol;
}
//獲得請求的方法
public String getRequestMethod(){
return requestMethod;
}
//獲得請求的路徑
public String getRequestPath(){
return requestPath;
}
//獲得請求的消息報頭
public Map<String,String> getRequestHeader(){
return this.hmHeader;
}
//根據(jù)參數(shù)的名字獲得請求帶過來的參數(shù)值
public String getParameter(String parameterName){
return hmparameters.get(parameterName);
}
//判斷當前請求的否是靜態(tài)資源
public boolean isStaticResource(){
return true;
}
//判斷當前請求的否是動態(tài)資源
public boolean isDynamicResource(){
return true;
}
//判斷當前請求的否是為空請求(有些瀏覽器會自動發(fā)送空請求)
public boolean isNullRequest(){
return isNullRequest;
}
}
以上內(nèi)容是對客戶端(瀏覽器)請求內(nèi)容的處理,即如何進行包裝客戶端請求的信息,并且將其包裝成一個統(tǒng)一的整體,既然能夠獲取瀏覽器的內(nèi)容,那么,我們就必須采取一定的措施告訴瀏覽器我們找到了你想要的文件,并且將返回給客戶端,下面我們就來實現(xiàn)如何返回給客戶端想要的信息
二、response響應處理
1、了解response響應
服務器在接收和解釋客戶端的請求消息后,服務器會返回給客戶端一個HTTP響應消息,我們稱之為響應(response)。其實也是一個按照http協(xié)議的規(guī)則拼接而成的一個字符串
HTTP響應也是由三個部分組成,分別是: 響應狀態(tài)行、消息報頭、響應正文
第一部分 響應狀態(tài)行
格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
例如:
HTTP/1.1 200 OK
各部分分別為:
HTTP-Version表示服務器HTTP協(xié)議的版本;
Status-Code表示服務器發(fā)回的響應狀態(tài)代碼;
Reason-Phrase表示狀態(tài)代碼的文本描述。
CRLF表示回車和換行
第二部分 消息報頭
HTTP消息報頭包括普通報頭、請求報頭、響應報頭、實體報頭這四大類。
每一個 報頭域 都是由 名字+冒號+空格+值 組成,消息報頭域的名字不區(qū)分大小寫。它們的作用是描述 客戶端或者服務器 的屬性
1.普通報頭:即可用于請求,也可用于響應,是作為一個整體而不是特定資源與事務相關(guān)聯(lián)。
2.請求報頭:允許客戶端傳遞關(guān)于自身信息和希望的響應形式。
3.響應報頭:允許服務器傳遞關(guān)于自身信息的響應。
4.實體報頭:定義被傳送資源的信息。即可用于請求,也可用于響應。
什么是 MIME Type?
首先,我們要了解瀏覽器是如何處理內(nèi)容的。在瀏覽器中顯示的內(nèi)容有 HTML、有 XML、有 GIF、還有 Flash ……那么,瀏覽器是如何區(qū)分它們,決定什么內(nèi)容用什么形式來顯示呢?答案是 MIME Type,也就是該資源的媒體類型。媒體類型通常是通過 HTTP 協(xié)議,由 Web 服務器告知瀏覽器的,更準確地說,是通過響應的消息報頭里面的屬性 Content-Type 來表示的,例如:Content-Type: text/HTML表示內(nèi)容是 text/HTML 類型,也就是超文本文件。為什么是“text/HTML”而不是“HTML/text”或者別的什么?MIME Type 不是個人指定的,是經(jīng)過 ietf 組織協(xié)商,以 RFC 的形式作為建議的標準發(fā)布在網(wǎng)上的,大多數(shù)的 Web 服務器和用戶代理都會支持這個規(guī)范 (順便說一句,Email 附件的類型也是通過 MIME Type 指定的)。
通常只有一些在互聯(lián)網(wǎng)上獲得廣泛應用的格式才會獲得一個 MIME Type,如果是某個客戶端自己定義的格式,一般只能以 application/x- 開頭。XHTML 正是一個獲得廣泛應用的格式,因此,在 RFC 3236 中,說明了 XHTML 格式文件的 MIME Type 應該是 application/xHTML+XML。當然,處理本地的文件,在沒有人告訴瀏覽器某個文件的 MIME Type 的情況下,瀏覽器也會做一些默認的處理,這可能和你在操作系統(tǒng)中給文件配置的 MIME Type 有關(guān)。比如在 Windows 下,打開注冊表的“HKEY_LOCAL_MACHINESOFTWAREClassesMIMEDatabaseContent Type”主鍵,你可以看到所有 MIME Type 的配置信息
每個MIME類型由兩部分組成,前面是數(shù)據(jù)的大類別,例如聲音audio、圖象image等,后面定義具體的種類。
常見的MIME類型
超文本標記語言文本 .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
第三部分 響應正文
響應正文就是服務器返回的資源的內(nèi)容
2、實現(xiàn)
首先,我們需要進行抽象,即將瀏覽器想要的信息,即如下內(nèi)容包裝起來,如下所示,我們將其包裝成一個接口,在抽象時我們必須認識到用戶可能會犯的錯誤,所以盡量使用重載的方法進行避免,在下面的接口中,使用了重載進行處理部分方法:
package com.sample.http;
import java.io.OutputStream;
import java.io.PrintWriter;
//http協(xié)議的響應
public interface HttpResponse {
//獲得一個指向客戶端的字節(jié)流
public OutputStream getOutputStream()throws Exception;
//獲得一個指向客戶端的字符流
public PrintWriter getPrintWriter()throws Exception;
//設置響應的狀態(tài)行 參數(shù)為String類型
public void setStatusLine(String statusCode);
//設置響應的狀態(tài)行 參數(shù)為int類型
public void setStatusLine(int statusCode);
//設置響應消息報頭
public void setResponseHeader(String hName,String hValue);
//設置響應消息報頭中Content-Type屬性
public void setContentType(String contentType);
//設置響應消息報頭中Content-Type屬性 并且同時設置編碼
public void setContentType(String contentType,String charsetName);
//設置CRLF 回車換行 \r\n
public void setCRLF();
//把設置好的響應狀態(tài)行、響應消息報頭、固定空行這三部分寫給瀏覽器
public void printResponseHeader();
//把響應正文寫給瀏覽器
public void printResponseContent(String requestPath);
}
在接口中,我們能夠看到詳細的解釋,下面我們就來實現(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é)議的響應
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();//初始化,記得,否則以下的操作會遇見空指針異常
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();
}
}
//獲得一個指向客戶端的字節(jié)流
public OutputStream getOutputStream()throws Exception
{
return os;
}
//獲得一個指向客戶端的字符流
public PrintWriter getPrintWriter()throws Exception
{
return pw;
}
//設置響應的狀態(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();
}
//設置響應的狀態(tài)行 參數(shù)為int類型
public void setStatusLine(int statusCode)
{
setStatusLine(statusCode+"");//將int類型轉(zhuǎn)化為String類型
}
//設置響應消息報頭
public void setResponseHeader(String hName,String hValue)
{
sbuffer.append(hName+": "+hValue);
setCRLF();
}
//設置響應消息報頭中Content-Type屬性
public void setContentType(String contentType)
{
setResponseHeader("Content-Type",contentType);
}
//設置響應消息報頭中Content-Type屬性 并且同時設置編碼
public void setContentType(String contentType,String charsetName)
{//text/html;charset=utf-8
setContentType(";charset= "+charsetName);
}
//設置CRLF 回車換行 \r\n
public void setCRLF()
{
sbuffer.append("\r\n");
}
//把設置好的響應狀態(tài)行、響應消息報頭、固定空行這三部分寫給瀏覽器
public void printResponseHeader()
{
//設置setResponseLine,setResponseHeader,setResponseType
String res=sbuffer.toString();
pw.print(res);
pw.flush();
}
//把響應正文寫給瀏覽器
public void printResponseContent(String requestPath)
{
//響應正文
String getPath= requestPath;//客戶請求的地址
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);//字符流寫過去是一個地址,因為寫過去之后需要瀏覽器解析,如果是圖片或者其他(圖片或視頻是字節(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中寫完以上代碼我們會發(fā)現(xiàn),其中有多處錯誤信息,其原因是我們沒有進行創(chuàng)建以上代碼所要求的類,現(xiàn)在我們進行創(chuàng)建,其使用方法請參見:java.util 類 Properties ,使用參考中的方法,我們能夠進行對所需要的信息進行配置,在以上代碼中使用的地方有兩處,分別是【注意:這樣做的好處是增減了項目的靈活性,用戶能夠在不查看代碼的情況下隨時更改配置文件等一些文件的信息,】:
(1)設置狀態(tài)行處
//設置響應的狀態(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)建如下所示,而對于status_code.properties文件存放在下載的準備文件中的/webservlet/project/中,直接復制到項目中即可:
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) {//輸出測試
//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)響應正文處:
//響應正文
String getPath= requestPath;//客戶請求的地址
String webHome=(new ConfigUtils()).getConfigValue("rootPath");
System.out.println("配置文件中目錄:"+webHome);//輸出從配置文件中獲取的地址
file=new File(webHome+getPath);
在響應正文中使用了ConfigUtils類進行了項目路徑的獲取,代碼如下所示,對于config.properties(注意:此文件中文件路徑應該注意,我使用的是Linux系統(tǒng),文件結(jié)構(gòu)是/home/***,而對于windows系統(tǒng),目錄結(jié)構(gòu)為:"C://webapps/*****,最好在地址欄復制地址,寫到配置中")文件也在準備文件中,請自行下載,然后復制到項目中:就是下面這個東西,路徑配置合適,然后你就可以將自己的項目放在webapps目錄下,讓自己的電腦作為服務器供其他人訪問自己的網(wǎng)站了

ConfigUtils路徑配置類,用于獲取項目文件目錄位置
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) {//輸出測試
// Properties p=new Properties();
// p.setProperty("rootPath","ddd");
// System.out.println(p.get("rootPath"));
System.out.println(getConfigValue("rootPath"));
}
}
到此為止,我們已經(jīng)實現(xiàn)了服務器的主要任務,接受請求和處理請求,下面我們進行測試:
寫一個測試類如下:
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);
// 用于測試收到的信息
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());
}
//寫響應給瀏覽器
/*
* 封裝:
* */
//輸出流
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 ,能夠看到瀏覽器解析后的界面,當其他電腦訪問時(其他電腦指的是同一個域內(nèi)的),只要將127.0.0.1修改為本地的ip地址即可

此時控制臺上也輸出相應的信息:

web服務器項目中靜態(tài)請求和動態(tài)請求處理:http://chabaoo.cn/article/191243.htm
到此這篇關(guān)于淺談web服務器項目中request請求和response的相關(guān)響應處理的文章就介紹到這了,更多相關(guān)web服務器 request請求 response響應處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java讀取文件:char的ASCII碼值=65279,顯示是一個空字符的解決
這篇文章主要介紹了java讀取文件:char的ASCII碼值=65279,顯示是一個空字符的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08

