目录
HTTP协议
一、HTTP协议概念:
概念:超文本传输协议,规定了浏览器和服务器之间数据传输的规则
二、HTTP协议的特点
- 基于TCP协议:面向链接,安全
- 基于请求-响应模型的:一次请求对应一次响应
- HTTP协议是无状态的协议:对于事物处理没有记忆能力,每次 - - 请求-响应都是独立的.
- 缺点:多次请求间不能共享数据
- 优点:速度快
三、Http请求过程
HTTP协议采用请求/响应模式,客户端向服务器发送一个请求报文,然后服务器响应请求。
下面介绍一下一次HTTP请求的过程:
- 域名解析:使用DNS协议进行域名解析
1.1 浏览器搜索自己的DNS缓存
1.2 如果浏览器自身缓存里找不到,就会去搜索操作系统自身的DNS缓存
1.3 以上两个都无,则尝试从操作系统的hosts文件里面找位置一般在C:\Windows\System32\drivers\etc\hosts)
1.4 上面三个过程都没有获取到的话,就递归的去域名服务器去查找 - 建立连接:发起TCP三次握手
- 发起http请求:建立TCP连接成功后,浏览器发起http请求
- HTTP是一个客户端和服务器端请求和应答的标准(TCP)。客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求。
通俗来讲,他就是计算机通过网络进行通信的规则,是一个基于请求与响应,无状态的,应用层的协议,常基于TCP/IP协议传输数据。目前任何终端(手机,笔记本电脑。。)之间进行任何一种通信都必须按照Http协议进行,否则无法连接。
- HTTP是一个客户端和服务器端请求和应答的标准(TCP)。客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求。
- 响应http请求:服务端响应http请求,浏览器得到返回response
- 浏览器向服务器发出请求后,服务器会对其进行应答,应答内容包括:协议的版本号和应答状态码 :HTTP/1.1 200
OK,响应头信息来记录服务器自己的数据,被请求的文档内容。最后发送一个空白行来表示头信息的发送到此为结束,接着以Content-Type响应头信息所描述的格式发送用户所请求的实际数据.
- 浏览器向服务器发出请求后,服务器会对其进行应答,应答内容包括:协议的版本号和应答状态码 :HTTP/1.1 200
- 解析response:浏览器解析response,并请求其它的资源(如js、css等)
- 浏览器接收服务器应答回来的 html 代码和css,和js代码再进行页面的渲染或者接收到应答的文件进行保存等操作
- 浏览器渲染展示页面:浏览器根据内核对页面进行渲染展示.
- 根据解析内容渲染呈现给用户
- 断开连接:TCP四次挥手
- 看java基础网络编程
四、请求数据的格式
1、 请求数据分为3部分:
- 请求行:请求数据的第一行,其中GET表示请求方式,/表示请求的资源路劲,HTTP/1.1表示协议版本
- 请求头:第二行开始,格式为key-value形式
- 请求体:POST请求的最后一部分,存放请求参数
2、常见HTTP请求头:
- Host:表示请求的主机名
- User-Agent:浏览器版本,例如:Chrome浏览器的表示类似
- ACCept:表示请求方希望的资源类型,或者能解解析识别的类型
- Accept-Languagen:表示浏览器编号的语言,服务器可以据此返回不同语言的网页
- Accept-Encoding:表示浏览器可以支持的压缩类型.
- Content-Type:表示实际发送的资源类型
- referrer:HTTP请求头中的 Referer,能解决部分防盗链问题.
3、防盗链: 网页在服务器中访问不了正确的网络图片,链接请求报403错误,而在浏览器中能正确访问
- 解决办法:
- 在页面的 head 里添加以下代码即可删除Referer请求头,对页面上的链接请求以及使用JavaScript代码发起的Ajax请求都有效。
<meta name="referrer" content="no-referrer" />
或者针对图片去掉referrer:
- 在页面的 head 里添加以下代码即可删除Referer请求头,对页面上的链接请求以及使用JavaScript代码发起的Ajax请求都有效。
<img referrer="no-referrer|origin|unsafe-url" src="image link"/>
<!-- 比如 -->
<img src="https://gitee.com/alanway/resources/raw/master/files/iis-reverse-proxy/site-access-with-proxy.png" referrerpolicy="no-referrer">
4、请求方法
HTTP/1.1有7种请求方法:1、GET;2、POST;3、PUT;4、DELETE;5、HEAD;6、TRACE;7、OPTIONS;
GET | 对这个资源的查操作 |
---|---|
DELETE | 对这个资源的删操作(注意:客户端无法保证删除操作一定会被执行,因为HTTP规范允许服务器在不通知客 户端的情况下撤销请求) |
HEAD | 与GET方法的行为很类似,但服务器在响应中只返回实体的头部分。可以快速获取资源信息,比如资源类型; 通过查看响应中的状态码,可以确定资源是否存在; 通过查看首部,测试资源是否被修改; |
POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。(适用于更新操作) |
PUT | 从客户端向服务器传送的数据取代指定的文档的内容。(适用于添加操作) |
OPTIONS | 用于获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET, POST” |
TRACE | 会在目的服务器端发起一个“回环”诊断,因为客户端在发起一个请求时,这个请求可能要穿过防火墙、代理、网关、或者其它的一些应用程序。这中间的每个节点都可能会修改原始的HTTP请求,TRACE方法允许客户端在最终将请求发送服务器时,它变成了什么样子。由于有一个“回环”诊断,在请求最终到达服务器时,服务器会弹回一条TRACE响应,并在响应主体中携带它收到的原始请求报文的最终模样。这样客户端就可以查看HTTP请求报文在发送的途中,是否被修改过了 |
五、GET请求和POST请求的区别(面试题)
- GET请求参数在请求行中,没有请求体.POST请求请求参数在请求体中
- GET请求请求参数大小有限制,POST没有限制
- GET请求的速度相对于POST快点
六、响应数据格式介绍
1、响应数据分为3部分
- 响应行:响应数据的第一行,其中HTTP/1.1表示协议版本,200 表示响应状态码,ok表示状态码描述
- 响应头:第二行开始,格式为key:value形式
- 响应体:最后一部分,存放响应数据
2、常见的HTTP响应头
- Content-Type:表示实际发送的资源类型
- 在HTTP协议消息头中,使用Content-Type来表示媒体类型信息。它被用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析html或仅仅展示一个文本等。
- Post请求的内容放置在请求体中,Content-Type定义了请求体的编码格式。数据发送出去后,还需要接收端解析才可以。接收端依靠请求头中的Content-Type字段来获知请求体的编码格式,最后再进行解析。
- Content-Length:表示该响应内容的长度(字节数)
- Contenet-Encoding:表示该响应压缩算法,例如gzip
- Cache-Control:表示客户端应如何缓存,例如max-age=300,表示最多可以缓存300秒.
3、状态码大类
- 1xx:响应中-临时状态码,表示请求已经接收,告诉客户端应该继续请求或者如果他已经完成则忽略它
- 2xx:成功-表示请求已经被成功接收,处理已完成 3xx:重定向-重定向到其它地方,它让客户端再发起一个请求已完成整个处理.
- 4xx:客户端错误-处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等
- 5xx:服务端错误-处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等
4、常见的响应状态码:
状态码 | 状态码英文名称 | 中文描述 |
---|---|---|
100 | Continue | 继续。客户端应继续其请求 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
200 | OK | 请求成功。一般用于GET与POST请求 |
201 | Created | 已创建。成功请求并创建了新的资源 |
202 | Accepted | 已接受。已经接受请求,但未处理完成 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
306 | Unused | 已经被废弃的HTTP状态码 |
307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
402 | Payment Required | 保留,将来使用 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
405 | Method Not Allowed | 客户端请求中的方法被禁止 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
409 | Conflict | 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突 |
410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | Precondition Failed | 客户端请求信息的先决条件错误 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
416 | Requested range not satisfiable | 客户端请求的范围无效 |
417 | Expectation Failed(预期失败) | 服务器无法满足请求头中 Expect 字段指定的预期行为。 |
418 | I’m a teapot | 状态码 418 实际上是一个愚人节玩笑。它在 RFC 2324 中定义,该 RFC 是一个关于超文本咖啡壶控制协议(HTCPCP)的笑话文件。在这个笑话中,418 状态码是作为一个玩笑加入到 HTTP 协议中的。 |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
5、常见数据传输格式
- application/x-www-form-urlencoded:
- 是最常见的 POST 提交数据的方式,浏览器的原生表单如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据,它是未指定属性时的默认值。 数据发送过程中会对数据进行序列化处理,以键值对形式?key1=value1&key2=value2的方式发送到服务器。 数据被编码成以 ‘&’ 分隔的键-值对, 同时以 ‘=’ 分隔键和值。非字母或数字的字符会被 percent-encoding。在axios中当请求参数为qs.stringify(data)时,会以此方式提交数据。后台如果使用对象接收的话,可以自动封装成对象。
- 优势: 所有浏览器都兼容。
- 问题:在数据结构及其复杂时,服务端数据解析变得很难
- application/json:
- 随着 json 规范的越来越流行,并且对浏览器支持程度原来越好,许多开发人员在请求头中加入 content-type: application/json ,这样做可以方便的提交复杂的结构化数据,这样特别适合restful接口。它告诉服务器请求的主体内容是 json 格式的字符串,服务器端会对json字符串进行解析,json 格式要支持比键值对复杂得多的结构化数据。这种方式的好处就是前端人员不需要关心数据结构的复杂度,只需要标准的json格式就能提交成功。当在 axios 中请求参数为普通对象时,POST 请求默认发送的是 application/json 格式的数据。 application/json 需要封装成对象的话,可以加上 @RequestBody 进行注解。
- 优势:是前端不需要关心数据结构的复杂度,后端解析方便。
- 问题:少数浏览器不兼容。
- multipart/form-data:
- 主要用于文件上传,将文件转成二进制数据进行传输,不涉及转码。
- text/plain:
- 是使用纯文本进行传输,平时用的很少
七、封装响应枚举类
响应结果枚举,用于提供给GraceJSONResult返回给前端的本枚举类中包含了很多的不同的状态码供使用,可以自定义,便于更优雅的对状态码进行管理,一目了然。
/**
* 响应结果枚举,用于提供给GraceJSONResult返回给前端的
* 本枚举类中包含了很多的不同的状态码供使用,可以自定义
* 便于更优雅的对状态码进行管理,一目了然
*/
public enum ResponseStatusEnum {
SUCCESS(200, true, "操作成功!"),
FAILED(500, false, "操作失败!"),
// 50x
UN_LOGIN(501,false,"请登录后再继续操作!"),
TICKET_INVALID(502,false,"会话失效,请重新登录!"),
NO_AUTH(503,false,"您的权限不足,无法继续操作!"),
MOBILE_ERROR(504,false,"短信发送失败,请稍后重试!"),
SMS_NEED_WAIT_ERROR(505,false,"短信发送太快啦~请稍后再试!"),
SMS_CODE_ERROR(506,false,"验证码过期或不匹配,请稍后再试!"),
USER_FROZEN(507,false,"用户已被冻结,请联系管理员!"),
USER_UPDATE_ERROR(508,false,"用户信息更新失败,请联系管理员!"),
USER_INACTIVE_ERROR(509,false,"请前往[账号设置]修改信息激活后再进行后续操作!"),
USER_INFO_UPDATED_ERROR(5091,false,"用户信息修改失败!"),
USER_INFO_UPDATED_NICKNAME_EXIST_ERROR(5092,false,"昵称已经存在!"),
USER_INFO_UPDATED_IMOOCNUM_EXIST_ERROR(5092,false,"账号已经存在!"),
USER_INFO_CANT_UPDATED_IMOOCNUM_ERROR(5092,false,"账号无法修改!"),
FILE_UPLOAD_NULL_ERROR(510,false,"文件不能为空,请选择一个文件再上传!"),
FILE_UPLOAD_FAILD(511,false,"文件上传失败!"),
FILE_FORMATTER_FAILD(512,false,"文件图片格式不支持!"),
FILE_MAX_SIZE_500KB_ERROR(5131,false,"仅支持500kb大小以下的图片上传!"),
FILE_MAX_SIZE_2MB_ERROR(5132,false,"仅支持2MB大小以下的图片上传!"),
FILE_NOT_EXIST_ERROR(514,false,"你所查看的文件不存在!"),
USER_STATUS_ERROR(515,false,"用户状态参数出错!"),
USER_NOT_EXIST_ERROR(516,false,"用户不存在!"),
// 自定义系统级别异常 54x
SYSTEM_INDEX_OUT_OF_BOUNDS(541, false, "系统错误,数组越界!"),
SYSTEM_ARITHMETIC_BY_ZERO(542, false, "系统错误,无法除零!"),
SYSTEM_NULL_POINTER(543, false, "系统错误,空指针!"),
SYSTEM_NUMBER_FORMAT(544, false, "系统错误,数字转换异常!"),
SYSTEM_PARSE(545, false, "系统错误,解析异常!"),
SYSTEM_IO(546, false, "系统错误,IO输入输出异常!"),
SYSTEM_FILE_NOT_FOUND(547, false, "系统错误,文件未找到!"),
SYSTEM_CLASS_CAST(548, false, "系统错误,类型强制转换错误!"),
SYSTEM_PARSER_ERROR(549, false, "系统错误,解析出错!"),
SYSTEM_DATE_PARSER_ERROR(550, false, "系统错误,日期解析出错!"),
// admin 管理系统 56x
ADMIN_USERNAME_NULL_ERROR(561, false, "管理员登录名不能为空!"),
ADMIN_USERNAME_EXIST_ERROR(562, false, "管理员登录名已存在!"),
ADMIN_NAME_NULL_ERROR(563, false, "管理员负责人不能为空!"),
ADMIN_PASSWORD_ERROR(564, false, "密码不能为空后者两次输入不一致!"),
ADMIN_CREATE_ERROR(565, false, "添加管理员失败!"),
ADMIN_PASSWORD_NULL_ERROR(566, false, "密码不能为空!"),
ADMIN_NOT_EXIT_ERROR(567, false, "管理员不存在或密码错误!"),
ADMIN_FACE_NULL_ERROR(568, false, "人脸信息不能为空!"),
ADMIN_FACE_LOGIN_ERROR(569, false, "人脸识别失败,请重试!"),
CATEGORY_EXIST_ERROR(570, false, "文章分类已存在,请换一个分类名!"),
// 媒体中心 相关错误 58x
ARTICLE_COVER_NOT_EXIST_ERROR(580, false, "文章封面不存在,请选择一个!"),
ARTICLE_CATEGORY_NOT_EXIST_ERROR(581, false, "请选择正确的文章领域!"),
ARTICLE_CREATE_ERROR(582, false, "创建文章失败,请重试或联系管理员!"),
ARTICLE_QUERY_PARAMS_ERROR(583, false, "文章列表查询参数错误!"),
ARTICLE_DELETE_ERROR(584, false, "文章删除失败!"),
ARTICLE_WITHDRAW_ERROR(585, false, "文章撤回失败!"),
ARTICLE_REVIEW_ERROR(585, false, "文章审核出错!"),
ARTICLE_ALREADY_READ_ERROR(586, false, "文章重复阅读!"),
// 人脸识别错误代码
FACE_VERIFY_TYPE_ERROR(600, false, "人脸比对验证类型不正确!"),
FACE_VERIFY_LOGIN_ERROR(601, false, "人脸登录失败!"),
// 系统错误,未预期的错误 555
SYSTEM_ERROR(555, false, "系统繁忙,请稍后再试!"),
SYSTEM_OPERATION_ERROR(556, false, "操作失败,请重试或联系管理员"),
SYSTEM_RESPONSE_NO_INFO(557, false, ""),
SYSTEM_ERROR_GLOBAL(558, false, "全局降级:系统繁忙,请稍后再试!"),
SYSTEM_ERROR_FEIGN(559, false, "客户端Feign降级:系统繁忙,请稍后再试!"),
SYSTEM_ERROR_ZUUL(560, false, "请求系统过于繁忙,请稍后再试!");
// 响应业务状态
private Integer status;
// 调用是否成功
private Boolean success;
// 响应消息,可以为成功或者失败的消息
private String msg;
ResponseStatusEnum(Integer status, Boolean success, String msg) {
this.status = status;
this.success = success;
this.msg = msg;
}
public Integer status() {
return status;
}
public Boolean success() {
return success;
}
public String msg() {
return msg;
}
}
import java.util.Map;
/**
* 自定义响应数据类型枚举升级版本
*
* @author 小Ti客栈
* @version V2.0
* @Title: IMOOCJSONResult.java
* @Package com.imooc.utils
* @Description: 自定义响应数据结构
*/
public class GraceJSONResult {
// 响应业务状态码
private Integer status;
// 响应消息
private String msg;
// 是否成功
private Boolean success;
// 响应数据,可以是Object,也可以是List或Map等
private Object data;
/**
* 成功返回,带有数据的,直接往OK方法丢data数据即可
*
* @param data
* @return
*/
public static GraceJSONResult ok(Object data) {
return new GraceJSONResult(data);
}
/**
* 成功返回,不带有数据的,直接调用ok方法,data无须传入(其实就是null)
*
* @return
*/
public static GraceJSONResult ok() {
return new GraceJSONResult(ResponseStatusEnum.SUCCESS);
}
public static GraceJSONResult okMsg(String msg) {
return new GraceJSONResult(ResponseStatusEnum.SUCCESS, msg);
}
public GraceJSONResult(Object data) {
this.status = ResponseStatusEnum.SUCCESS.status();
this.msg = ResponseStatusEnum.SUCCESS.msg();
this.success = ResponseStatusEnum.SUCCESS.success();
this.data = data;
}
/**
* 错误返回,直接调用error方法即可,当然也可以在ResponseStatusEnum中自定义错误后再返回也都可以
*
* @return
*/
public static GraceJSONResult error() {
return new GraceJSONResult(ResponseStatusEnum.FAILED);
}
/**
* 错误返回,map中包含了多条错误信息,可以用于表单验证,把错误统一的全部返回出去
*
* @param map
* @return
*/
public static GraceJSONResult errorMap(Map map) {
return new GraceJSONResult(ResponseStatusEnum.FAILED, map);
}
/**
* 错误返回,直接返回错误的消息
*
* @param msg
* @return
*/
public static GraceJSONResult errorMsg(String msg) {
return new GraceJSONResult(ResponseStatusEnum.FAILED, msg);
}
/**
* 错误返回,token异常,一些通用的可以在这里统一定义
*
* @return
*/
public static GraceJSONResult errorTicket() {
return new GraceJSONResult(ResponseStatusEnum.TICKET_INVALID);
}
/**
* 自定义错误范围,需要传入一个自定义的枚举,可以到[ResponseStatusEnum.java[中自定义后再传入
*
* @param responseStatus
* @return
*/
public static GraceJSONResult errorCustom(ResponseStatusEnum responseStatus) {
return new GraceJSONResult(responseStatus);
}
public static GraceJSONResult exception(ResponseStatusEnum responseStatus) {
return new GraceJSONResult(responseStatus);
}
public GraceJSONResult(ResponseStatusEnum responseStatus) {
this.status = responseStatus.status();
this.msg = responseStatus.msg();
this.success = responseStatus.success();
}
public GraceJSONResult(ResponseStatusEnum responseStatus, Object data) {
this.status = responseStatus.status();
this.msg = responseStatus.msg();
this.success = responseStatus.success();
this.data = data;
}
public GraceJSONResult(ResponseStatusEnum responseStatus, String msg) {
this.status = responseStatus.status();
this.msg = msg;
this.success = responseStatus.success();
}
public GraceJSONResult() {
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
}