网络——深入了解Http

本文详细探讨了HTTP网络请求的原理,包括HTTP请求服务器的方法、报文格式解析、每个请求的具体HTTP报文分析,以及如何借助TCP模拟HTTP传输。通过学习,读者将能够深入理解HTTP通信过程。
摘要由CSDN通过智能技术生成

一、Http网络请求的原理

Http是通过TCP实现的可靠的网络传输。(需要了解的知识TCP/UDP编程)
那么Http是如何过度到TCP实现客户端与服务器的交互的呢?
①、当客户端执行网络请求的时候,会从URL地址中解析出URL的主机名(Host),并将主机地址转换成IP
(主机名是什么:类似http://write.blog.csdn.net/postedit 
    IP是什么:类似192.168.1.1。主机名是IP的表示,因为主机名表达的含义肯定比数字容易记住
②、从URL解析出服务器的所用的端口号。
③、客户端用TCP连接服务器
④、连接成功之后,获取输出流,并将数据以报文(报文的格式之后再讲)的形式传递给服务器(Request)
⑤、当服务器接受到数据之后,进行判断和解析吗,并回送一条响应报文(Response)
⑥、客户端从输入流中获取报文,并解析。
⑦、最后关闭网络的连接。

二、Http请求服务器的方式。(详细知识,需要了解报文的格式,之后才能做实验)

①、GET请求
作用:获取服务器的某个资源,或者说是告诉服务器,我想查询一些信息。
特点:明文传输(直接将传送给服务器的数据,写在URL上)。
常用:跳转到另一个网站,网站名就是GET传输,然后向服务器请求获取该网站。

②、POST请求
作用:向服务器传递数据。一般用来提交HTML表单时使用。服务器处理这些数据
特点:表单上传。(写入的数据,不显示在URL上)
常用:注册用户名、密码。传送给服务器处理。

其实,从作用上看,两者其实没有什么区别,都是Client传输数据给Service。不过一个是写在URL上,一个是写在form表单上。然后Service端根据这些上传的数据进行处理。

③、PUT请求
作用:向服务器写入资源。在服务器创造一个文本,然后将Client端的数据,PUT到该文本中。(如果文本名重复的话,前一个文件的内容就会被覆盖)

④、DELETE请求
作用:从服务器中删除资源。(无法保证是否被删除,HTTP规范允许不通知客户端拒绝该请求)

⑤、HEAD请求
作用:让Service端只返回报文的头部(报文分为三部分:状态、头部、数据)。Client端根据报文的头部,能够判断(数据域的信息,判断该报文是否存在数据等。原理需要讲到报文的时候才能说清楚)

⑥、TRACE请求
作用:当Client端发送请求时候,可能需要经过防火墙、代理、网关等应用程序,这些程序可能会修改原始的HTTP请求,然后将最终的HTTP发送给Service端。当Service端接收之后,会回调将修改后的HTTP请求,回传给Client端。

⑦、OPTION请求
作用:询问服务器支持哪些方法(比如POST、GET、OPTION方法)


三、如何解析HTTP报文

①、请求报文的格式
<起始行>
<首部>
<空行>
<数据域>

示例:
GET http://my.csdn.net/my/mycsdn HTTP1.1
Content-Type:text/plain
Host:www.my.csdn.net
Content-Length:30

username="chen"&pwd = 123

②、回复报文的格式
<状态栏>
<首部>
<空行>
<数据>
从格式,来看其实就是状态栏不太一样。
Respone的状态栏:版本号  状态码  对状态码的描述 
版本号就没什么好说的。
状态码是什么:
100~199:表示请求以及接收到了
200~299:请求成功。Service已经处理
300~399:要求完成请求需要更进一步的动作
400~499:客户端错误。表示请求语法错误,或者是请求无法执行
500~599:服务器端错误。服务器无法实现请求。

常用状态码:(状态码,后面的就是描述)
200 OK:客户端请求成功
400 Bad Request:客户端请求语法有错。
403 Forbidden:服务器接受到请求,但是拒绝服务
404 Not Found:请求资源不存在。可能原因:URL错误
500 Internal Server Error:服务器发生不可预期错误
503 Server Unavailable:服务器当前无法处理客户端请求

示例:
HTTP1.1 200 OK :表示成功接收

③、首部的属性
首部的分类:①、请求的首部属性  ②、响应的首部属性  ③、通用的首部属性  ④、自定义的首部属性
介绍请求的首部属性:
Content-Type:请求数据的类型(MIME)
Content-Length:请求数据的长度
Cache-Control:是否缓存
Host:请求数据的主机名
User-Agent:发出请求的浏览器
Accept:客户端可识别的类型列表
Accept-Encoding:客户端可识别的类型编码
Connection:设置连接方式。KeepAlive表示保持连接
Transfer-Encoding:告诉接收端,为保证可靠传输,对报文采取了什么编码

重要的属性
Content-Type拥有的属性:
超文本标记语言文本 .html                     text/html
xml文档 .xml                                          text/xml
XHTML文档 .xhtml                                application/xhtml+xml
普通文本 .txt                                          text/plain
RTF文本 .rtf                                           application/rtf
PDF文档 .pdf                                         application/pdf
Microsoft Word文件 .word                     application/msword
PNG图像 .png                                       image/png
GIF图形 .gif                                           image/gif
JPEG图形 .jpeg,.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
Json数据:.json                                   application/json
任意的二进制数据                                application/octet-stream


四、解析每个请求的HTTP报文

①、GET请求  
例:输入http://write.blog.csdn.net/login.php?username=chen&pwd=123
直接将数据写在URL就是明文传输
则创建的报文是:
GET login.php/username=chen&pwd=123 HTTP1.1
Host:http://write.blog.csdn.net

服务器返回的报文数据:
HTTP/1.1 200 OK
Content-Type:text/html
Content-Length:1024

<Html>
  网页数据
</Html>

②、POST请求
例:从http://write.blog.csdn.net/login.php中,上传HTML表单
POST login.php HTTP1.1
Accept-Encoding:gzip
Content-Type:multipart/form-data; boundary=ABCD           //Content-Type:表示这是一个表单  boundary:表示分隔符
Content-Length:22350
Host:http://write.blog.csdn.net
Connection:Keep-Alive

--ABCD                                                                  //通过--加上boundary的值:表示这是表单的一个数据
Content-Disposition:form-data;name="username"                  //key值
Content-Type:text/plain; charset=UTF-8                                    //key的类型
Content-Transfer-Encoding:8bit                                              //key的大小
                                                                                                  //空白行,必须加
chen                                                                                          //value的值
--ABCD
Content-Disposition:form-data;name="images"; filename="storage/emulated/0/Camera/picture/tempeter.jpg"
Content-Type: application/octet-stream                      
Content-Transfer-Encoding:binary

(这里是图片的二进制数据)
--ABCD--    //表示终止



服务器返回的数据:
HTTP/1.1 200 OK
Content-Type:text/plain
Content-Length:21

success

③、PUT请求
PUT new-text.txt HTTP/1.1
Host:www.myhost.cn
Content-Type:text/html
Content-Length:21    

This  is file content           //文件的内容


服务器返回的数据:
HTTP/1.1 200 OK
Content-Type:text/html
Content-Length:1024
Location:www.myhost.cn/new-text.txt

www.myhost.cn/new-text.txt

④、HEAD请求
HEAD  login.php HTTP/1.1
Content-Type:text/plain
Content-Length:1024

服务器返回的数据
HTTP/1.1 200 OK
Content-Type:text/html
Content-Length:12324

⑤、TRANCE请求  假设经过了一层代理商(proxy.vpn.com)
TRANCE  login.php HTTP/1.1
Host:www.myhost.com

服务器返回的数据:
HTTP/1.1 200 OK
Content-Type:text/plain
Content-Length:21

TRANCE login.php HTTP/1.1
Host:www.myhost.com
Via:www.proxy.vpn.com


⑥、OPTION请求
OPTION login.php HTTP/1.1
Host:www.myhost.com

服务器返回的数据:
HTTP/1.1 200 OK
Allow:GET、POST、PUT、OPTIONS
Content-Length:0

五、利用TCP模拟HTTP传输

①、创建SimpleServer等待Socket连接。
public class SimpleServer extends Thread{
	public static final int PORT = 8000;
	private ServerSocket mServerSocket = null;
	public SimpleServer(){
		try {
			mServerSocket = new ServerSocket(PORT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("端口"+PORT+"已经被占用,请换一个端口");
		}
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		//死循环,接收客户端的TCP
		while(true && mServerSocket != null){
			System.out.println("等待客户端连接");
			//调用线程处理数据
		}
	}
}

②、TCP连接成功后,Server端处理数据(创建DeliverThread来处理数据)
public class DeliverThread extends Thread {

	private Socket mServerSocket;
	private BufferedReader mBufferedReader;
	private PrintWriter mPrintWriter;
	
	public DeliverThread(Socket socket){
		mServerSocket = socket;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		try {
			//获取输入输出流
			mBufferedReader = new BufferedReader(new InputStreamReader(mServerSocket.getInputStream()));
			mPrintWriter = new PrintWriter(mServerSocket.getOutputStream());
			//处理Client发送过来的数据
			parseRequest();
			//回复Client的数据
			handleResponse();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			try {
				mBufferedReader.close();
				mPrintWriter.close();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

		}
	}
	
	private void parseRequest() throws IOException{
		String line = null;
		int lineNum = 0;
		//首先解析头部状态数据
		//然后解析头部数据
		//最后解析传递的数据
		while((line = mBufferedReader.readLine()) != null){
			//如果为第一行,那么一定是状态栏
			if (lineNum == 0){
				parseHeaderLine(line);
			}
			lineNum++;
		}
		System.out.println("解析Service数据完成");
	}
	
	private void parseHeaderLine(String line){
		//分割Params
		String data[] = line.split(" ");
		System.out.println("请求类型"+data[0]);
		System.out.println("请求的网址"+data[1]);
		System.out.println("Http版本:"+data[2]);
	}
	
	private void handleResponse(){
		mPrintWriter.println("Http/1.1 200 OK");
		mPrintWriter.println("Content-Type:text/plain");
		mPrintWriter.println("Content-Length:300");
	}
}

③、创建Socket端。
ublic class HttpPost extends Thread {
	private String mUrl;
	private Map<String, String> mParams;
	private Socket mClientSocket;
	public HttpPost(String url){
		mUrl = url;
		mParams = new HashMap<>();
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		try {
			mClientSocket = new Socket(mUrl,SimpleServer.PORT);
			BufferedReader reader = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
			PrintWriter writer = new PrintWriter(mClientSocket.getOutputStream());
			writeHeader(writer);
			waitResponse(reader);
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			try {
				mClientSocket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private void writeHeader(PrintWriter writer){
		writer.println("POST login.php HTTP/1.1");
	}
	
	private void waitResponse(BufferedReader reader){
		StringBuilder builder = new StringBuilder();
		String str = null;
		try {
			while((str = reader.readLine()) != null){
				builder.append(str);
			}
			System.out.println(builder.toString());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void addParams(String key,String value){
		mParams.put(key,value);
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值