上一次我们分装了respon端,这次,我们要分析一下客户端的请求,提取一些有用的信息。比如,在客户端输入姓名,这个姓名的信息就存在HTTP协议的request端,我们如果想在服务器端增加一个功能:欢迎某某,这样就必须要分析request端的协议。
首先,我们写一个简单的HTML页面。新建一个文本文件,将后缀改成HTML,之后用Notepad打开,编辑
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>欢迎来到LPL全明星投票</title>
GET / HTTP/1.1
Host: localhost:7777
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
pgrade-Insecure-Requests: 1
</head>
<body>
<pre>
method :请求方式 get/post
action:请求的服务器路径
</pre>
<form method="get" action ="http://localhost:7777/index.html">
姓名ID:<input type ="text" name="uname" id="name"/>
Password:<input type="password" name="uname" id="name"/>
<input type="submit" value="登陆"/><br/>
EDG ClearLove:<input type="checkbox" name="fav" value="0"/>打野<br/>
RNG MLXG:<input type="checkbox" name="fav" value="1"/>打野<br/>
RNG UZI:<input type="checkbox" name="fav" value="2"/>ADC<br/>
IG Rookie:<input type="checkbox" name="fav" value="3"/>中单<br/>
THE SHY:<input type="checkbox" name="fav" value="4"/>上单<br/>
</form>
<p>段落</p>
</body>
</html>
这是一个非常简单的HTML页面,
HTML不具体深究,这里只需要记住HTML的关键字是成对出现的,然后具体的用法可以去百度或者查书。这里只是举例。
可以看到具体协议是:GET /index.html?uname=jianghe&uname=123456 HTTP/1.1
Host: localhost:7777
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
get和post的区别在上一篇的博客中讲解过。
package MyServer02;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 特别说明 请求应该是request
* 我拼写错了
* 妈的
*
*
* 请求方式:get post
* 请求url
* 请求的参数
* @author jh
*
*/
public class Requst {
//请求方式
private String method;
//请求资源
private String url;
//请求参数
private Map<String,List<String>> parameterMapValues;
//Accept-Encoding: gzip, deflate 一个请求的参数可能对应多个选项
//内部
public static final String CRLF="\r\n";
private InputStream is;
private String requestInfo;//public方便全局进行访问
public Requst() {
url="";
method="";
parameterMapValues=new HashMap<String,List<String>>();
requestInfo="";
}
public Requst(String Info) {
this();
requestInfo=Info;
}
public Requst(Socket client) throws IOException{
this(client.getInputStream());
}
public Requst(InputStream iStream) {
this();
this.is=iStream;
try {
byte[] data=new byte[20480];
int len=iStream.read(data);
if(len==-1) {
len=1;
}
requestInfo=new String(data, 0, len);
} catch (IOException e) {
// TODO Auto-generated catch block
return ;
}
//分析请求信息
parseRequestInfo();//在构造器中调用函数,这里非常重要
}
//parse从语法上描述或分析(词句等)
//params参数
//
public void parseRequestInfo() {
if (requestInfo==null||requestInfo.equals("")) {
System.out.print("nothing");
return ;
}
String paramString ="";
//获取请求方式
String firstLine=requestInfo.substring(0,requestInfo.indexOf(CRLF));
firstLine.trim();
this.method=firstLine.substring(0,firstLine.indexOf("/")).trim();
String strUrl=firstLine.substring(firstLine.indexOf("/"),firstLine.indexOf("HTTP"));
if(this.method.equalsIgnoreCase("post")) {//忽略大小写,get 和post的区别就在于是否含有参数
this.url=strUrl;
}else if (this.method.equalsIgnoreCase("get")) {
if(strUrl.contains("?")) {
String[] strarray=strUrl.split("\\?");
this.url=strarray[0];
paramString=strarray[1];
}else {
this.url=strUrl;
}
}
if(paramString.equals("")) {
return ;
}else {
parseParams(paramString);
}
}
//GET /index.html?uname=jianghe&uname=123456&fav=0&fav=1&fav=2 HTTP/1.1//这里面有参数
//uname=jianghe&uname=123456&fav=0&fav=1&fav=2
public void parseParams(String paramsString) {
String paramsarr[]=paramsString.split("&");
for(String temp:paramsarr) {
String mapparams[]=temp.split("=");
if(mapparams.length==1) {
//这里是属于第二种情况,需要进行扩容,方便以后共同处理
mapparams=Arrays.copyOf(mapparams, 2);
mapparams[1]=null;
}
String key=mapparams[0].trim();
String values= (null==mapparams[1])?null:mapparams[1];
//String values= null==mapparams[1]?null:mapparams[1];
if(!parameterMapValues.containsKey(key)) {
parameterMapValues.put(key, new ArrayList<String>());
}
List<String> values_arr=parameterMapValues.get(key);
values_arr.add(values);
}
}
public String[] getParameterarray(String name) {
List<String> valuesarr=null;
if((valuesarr=parameterMapValues.get(name))==null) {
return null;
}else {
return valuesarr.toArray(new String[0]);//这里是转型之后的数组类型
}
}
public String getParameter(String name) {//只返回第一个元素
String[] valuesarray=getParameterarray(name);
if(valuesarray==null) {
return null;
}else {
return valuesarray[0];
}
}
public void println() {
System.out.println("Hello");
for(String key:parameterMapValues.keySet()) {
List<String> values=parameterMapValues.get(key);
System.out.print(key+" ");
for(String value:values) {
System.out.println(value);
}
}
}
public String getMethod() {
return method;
}
public String getUrl() {
return url;
}
/*public static void main(String[] args) {
String info="GET /index.html?uname=jianghe&uname=123456 HTTP/1.1\r\n" +
"Host: localhost:7777\r\n" +
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0\r\n" +
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*;q=0.8\r\n" + */
/*"Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\n" +
"Accept-Encoding: gzip, deflate\r\n" +
"Connection: keep-alive\r\n" +
"Upgrade-Insecure-Requests: 1";
Requst requst=new Requst(info);//基本定位到是参数的map中没有参数
requst.getParameter("uname");
requst.println();
}*/
}
分装完成,主要说明一下一个参数的请求可能对应多个选项,所以使用map<string,list<string>>进行封装。另外构造器中调用分析头信息的函数。
另外针对这个封装,改写服务器端的代码;
package MyServer02;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server01 {
private ServerSocket serverSocket=null;
public static void main(String[] args) {
Server01 server01=new Server01();
server01.start();
server01.stop();
}
public void start() {
try {
serverSocket=new ServerSocket(7777);
this.receive();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void receive() {
try {
Socket client=serverSocket.accept();
/*String meg=null;
StringBuilder sbBuilder=new StringBuilder();
BufferedReader bReader=new BufferedReader(new InputStreamReader(client.getInputStream()));
while((meg=bReader.readLine()).length()>0) {
sbBuilder.append(meg);
sbBuilder.append("\r\n");
if(meg==null) {
break;
}
}
String re=sbBuilder.toString().trim();
System.out.println(re);
CloseUtil.CloseAll(bReader);*/
Response response=new Response(client);
//response.show();
Requst requst=new Requst(client.getInputStream());
//Request requst=new Request(client.getInputStream());
response.println("<html> <head><title>HTTP响应示例</title>");
response.println("</head><body>");
response.println("欢迎").println(requst.getParameter("uname")).println("归来");
response.println("</body></html>");
//requst.println();
response.pushtoclient(200);//此处还有错误,就是状态代码不起任何作用
//response.pushtoclient(404);*/
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void stop() {
}
}