URL的概念与组成
浏览某个网页时,很重要的是要知道某个网页的URL(统一资源定位符Uniform Resource Locator)。
以 https://www.baidu.com/index.php 为例:
通过URL的组成,可以看到当我们在浏览器中输入URL时,
其中的域名会被提取出来,并用DNS服务将其解析为IP地址。
之后就进行HTTP读物,建立连接,发送请求,接收应答消息,断开连接,
最终就会在浏览器上浏览到我们想要浏览的页面。
平时俗称的 “网址” 其实就是说的 URL:
urlencode 和 urldecode
urldecode 就是 urlencode 的逆过程
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成 %XY 格式
例:"+" 被转义成了 "%2B"
应用层协议:HTTP
全称:Hyper Text Transfer Protocol 超文本传输协议
是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)的协议。
HTTP协议工作于客户端-服务端架构为上。
浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。
Web服务器根据接收到的请求后,向客户端发送响应信息。
从层次的角度看,HTTP协议是一个应用层协议;
它是万维网上能够可靠地交换文件(包括文本、声音、图像等各种多媒体文件)的重要基础。
它可以使浏览器更加高效,使网络传输减少,
不仅保证计算机正确快速地传输超文本文档,
还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是我们浏览网页、看在线视频、听在线音乐等必须遵循的规则。
正是在这样的规则下,浏览器才能向万维网服务器发送万维网文档请求,
然后服务器会将请求的文档发送回浏览器。
在浏览器和服务器之间的请求和响应的交互,必须按照规定的格式和规则,
这些格式和规则就构成了超文本传输协议。
它所对应的传输层的协议是TCP的传输;
它所应用的传输层的端口是80号端口,另外还有一个备用端口是8080端口。
HTTP消息结构
HTTP是基于客户端/服务端(C/S)的架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议。
一个HTTP"客户端"是一个应用程序(Web浏览器或其他任何客户端),通过连接到服务器达到向服务器发送一个或多个HTTP的请求的目的。
一个HTTP"服务器"同样也是一个应用程序(通常是一个Web服务,如Apache Web服务器或IIS服务器等),通过接收客户端的请求并向客户端发送HTTP响应数据。
HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。
一旦建立连接后,数据消息就通过类似Internet邮件所使用的格式[RFC5322]和多用途Internet邮件扩展(MIME)[RFC2045]来传送。
HTTP协议格式
HTTP请求
请求格式:
请求报文:
请求报文(Request message)包含了四个部分的内容:
请求行(Request line)
头部(Headers)
空行(A blank line)
主体部分(Body)
请求行(Request line)包含了三部分的内容:
Request type
URL
HTTP version
URL全称:Uniform Resource Locator
统一资源定位符由四部分组成:
Method
Host
Port
Path
Request message:
Request message 详细格式:
Request line:
HTTP请求:
首行: [方法] + [url] + [版本]
Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
Body: 空行后面的内容都是Body. Body允许为空字符串.
如果Body存在, 则在Header中会有一个 Content-Length 属性来标识Body的长度
HTTP响应
响应格式:
响应报文:
响应报文(Response message)包含了四个部分的内容:
状态行(Status line)
头部(Headers)
空行(A blank line)
主体部分(Body)
状态行(Status line)包含了三部分的内容:
HTTP version
Status code
Status phrase
Response message:
Response message 详细格式:
Status line:
HTTP响应:
首行: [版本号] + [状态码] + [状态码解释]
Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
Body: 空行后面的内容都是Body. Body允许为空字符串.
如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在body中
HTTP工作过程:
一个HTTP的操作称为一个事物
它的工作过程分为四个步骤:
首先客户机和服务器需要建立TCP连接,这时HTTP开始工作了;
计算机系统中有一个专门为HTTP开放默认端口:80端口,
还有一个备用的8080端口,主要用于万维网传输信息的协议;
第二步当连接建立以后,客户机会发送一个请求给服务器,
请求具有专门的请求格式和请求报文,
请求的格式是统一资源定位符URL;
第三步是服务器接到请求以后,给予的相应的响应信息;
与请求类似,应答也有专门的格式与响应报文;
最后一步,当客户端收到服务器所返回的信息,
通过浏览器显示在用户的显示屏,接着客户机与服务器断开连接;
如果在这个过程当中,某一个步骤出现了错误,
那么产生错误的信息,将返回到客户端。
对应用户来说,这些过程是由HTTP自己完成的。
用户只要用鼠标点击,等待信息显示浏览即可。
所以用户能够看到的就是,在浏览器中间输入了你的对应的网页地址,
那么网页就显示在你的面前了。
步骤一:
首先客户机和服务器需要建立连接,这时HTTP开始工作了;
步骤二三:
第二步当连接建立以后,客户机会发送一个请求给服务器;
第三步是服务器接到请求以后,给予的相应的响应信息;
步骤四:
最后一步,当客户端收到服务器所返回的信息,
通过浏览器显示在用户的显示屏,接着客户机与服务器断开连接;
如果在这个过程当中,某一个步骤出现了错误,
那么产生错误的信息,将返回到客户端。
HTTP的工作究竟是如何完成的?
在双方建立连接之前,首先要知道对方的地址,那么怎样才能知道对方的地址呢?
就要通过DNS服务。
第一步是浏览器分析超链接,超链接中的域名被提取出来,
通过DNS服务得到对应的IP地址;
第二步,浏览器向DNS请求解析这个域名所对应的IP,
当得到这个IP地址以后,双方就可以开始建立连接的工作了;
第三步,双方之间可以建立起TCP的连接。
如下图:
HTTP是应用层的服务,那么在传输层它依靠的是一个可靠的面向连接的传输,TCP的传输。
TCP的传输在80端口或者8080这个端口完成,双方建立起连接以后可以进行下一步的工作。
下一步浏览器发出HTTP请求报文,
请求报文里面含有这样一个文件命令 GET/chn/yxsz/index.htm
意思是:希望得到chn文件夹下的yxsz文件夹下index.htm文件,
这实际上就是我们用户所需要的对应的网页文件。
当服务器收到HTTP的请求报文以后,
会按照这个路径到对应的文件夹下,取得对应的index.htm文件,
接着把这个文件组织到它的报文当中,反馈给我们的浏览器。
浏览器进行接收以后,会检查报文是否完整,
如果完整,双方之间的数据传输就完成了。
随后TCP连接可以被释放。
整个的TCP/IP三次握手结束以后,
HTTP协议还会在浏览器这一端对响应报文进行一个文件提取的工作。
它会将传过来的index.htm这个文件,按照超文本的格式在屏幕上显示出来,
所以用户这时就可以看到网页的全部内容了。
HTTP协议包括哪些请求?
GET:请求读取由URL所标志的信息。
POST:给服务器添加信息。
PUT:在给定的URL下存储一个文档。
DELETE:删除给定的URL所标志的资源。
两种常用的请求方式
在客户端发送请求时,有这两种常用的请求方式:GET 和 POST。
GET方式:
是以实体的方式得到由请求URL所指定资源的信息,
如果请求URL只是一个数据产生过程,
那么最终要在响应实体中返回的是处理过程的结果所指向的资源,
而不是处理过程的描述。
POST方式:
用来向目的服务器发出请求,要求它接受被附在请求后的实体,
并把它当作请求队列中请求URL所指定资源的附加新子项,
POST被设计成用统一的方法实现下列功能:
1.对现有资源的解释;
2.向电子公告栏、新闻组、邮件列表或类似讨论组发信息;
3.提交数据块;
4.通过附加操作来扩展数据库。
可以看出,GET是向服务器发索取数据的一种请求,
而POST是向服务器提交数据的一种请求,要提交的数据位于信息头后面的实体中。
POST 与 GET 的区别:
1)Get是从服务器上获取数据,Post是向服务器传送数据。
2)Get是把参数数据队列加到提交表单的Action属性所指向的URL中,
值和表单内各个字段一一对应,在URL中可以看到。
3)Get传送的数据量小,不能大于2KB;
Post传送的数据量较大,一般被默认为不受限制。
4)根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的。
I.安全的:意味着该操作用于获取信息而非修改信息。
换句话说,GET请求一般不应产生副作用。
就是说,它仅仅是获取资源信息,就像数据库查询一样,
不会修改,增加数据,不会影响资源的状态。
II.幂等的:意味着对同一URL的多个请求应该返回同样的结果。
HTTP 的状态码
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。
当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。
HTTP状态码的英文为HTTP Status Code。
比较详细的HTTP状态码列表
最常见的状态码:
200(OK), 404(Not Found), 403(Forbidden),
302(Redirect, 重定向), 504(Bad Gateway)
设置 HTTP 状态代码的方法:
方法 | 描述 |
---|---|
public void setStatus ( int statusCode ) | 该方法设置一个任意的状态码。setStatus 方法接受一个int(状态码)作为参数。如果您的反应包含了一个特殊的状态码和文档,请确保在使用 PrintWriter 实际返回任何内容之前调用 setStatus。 |
public void sendRedirect(String url) | 该方法生成一个 302 响应,连同一个带有新文档 URL 的 Location 头。 |
public void sendError(int code, String message) | 该方法发送一个状态码(通常为 404),连同一个在 HTML 文档内部自动格式化并发送到客户端的短消息。 |
HTTP 常见 Header
Content-Type: 数据类型(text/html等)
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配 3xx 状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
列举实例:
使用GET来传递数据的实例:
客户端请求:
GET /hello.txt HTTP/1.1
User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Host: www.example.com
Accept-Language: en, mi
服务端响应:
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain
输出结果:
Hello World! My payload includes a trailing CRLF.
Http Server
// 简易版的http server v1 + 多线程 + 手动构建 response,
// 展示 302 307 404 效果
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
/*
端口号
*/
private static final int PORT=9999;
/*
统一编码
*/
private static final String CHARSET="UTF-8";
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(PORT);
ExecutorService POOL= Executors.newCachedThreadPool();
try{
while(true){
Socket socket=serverSocket.accept();
POOL.submit(new Runnable() {
@Override
public void run() {
try{
BufferedReader reader=new BufferedReader(
new InputStreamReader(socket.getInputStream()));
// 解析Http请求行
String httpLine=reader.readLine();
System.out.println("==="+httpLine);
String[] httpLineArray=httpLine.split(" ");
String requestMethod=httpLineArray[0];
String requestUri=httpLineArray[1];
String requestVersion=httpLineArray[2];
// 解析请求头
String requestHeader;
Map<String,String> headers=new HashMap<>();
while((requestHeader=reader.readLine())!=null && requestHeader.length()!=0){
String[] headerArray=requestHeader.split(":");
headers.put(headerArray[0].trim(),headerArray[1].trim());
}
PrintWriter writer=new PrintWriter(
new OutputStreamWriter(socket.getOutputStream(),CHARSET), true);
String content;
if("/307".equals(requestUri)){
writer.println("HTTP/1.1 307 Temporary Redirect");
writer.println("Location: http://45.40.254.164");
content="";
}else if("/404".equals(requestUri)){
writer.println("HTTP/1.1 404 Not Found");
content="<h1>没有找到资源</h1>";
}else{
writer.println("HTTP/1.1 200 OK");
content="<h1>My Http Server</h1>";
}
writer.println("Content-Type:text/html; charset=utf-8");
writer.println("Context-Length:"+content.getBytes(CHARSET).length);
writer.println();
writer.println(content.toString());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}catch (Exception e){
e.printStackTrace();
}
}
}
IDEA截图:
http://localhost:9999/404:
http://localhost:9999:
http://localhost:9999/307:
CSDN 浅解:Servlet 客户端 HTTP 请求&响应
Http VS Https
http传送数据(包括账号和密码),都是明文传送,很容易被窃取或者侦听,在现有的互联网应用中,明显有不安全因素,
所以有了https,简单理解 https多一层加密解密层,在发送前加密,在收到后解密,在网络里传输的都是经过加密的数据。