什么是HTTP?
HTTP全称"超文本传输协议",是一种应用非常广泛的应用层协议.
理解"应用层协议"
我们学过TCP/IP协议, 已经知道目前数据可以从客户端进程经过路径算则, 跨网络传输到服务器进程, 可是, 仅仅是把数据从A传输到B点就完事了吗?
这就好比, 在饿了吗上面点了一个手抓饼, 卖家通过联系外卖员来将其送到买家手上, 这就完事了吗? 当然不是, 买家还要品尝这个手抓饼, 看味道是否正常,质量是否过关, 吃完之后还可以给卖家打分评论.
所以,我们把数据从A端传送到B端, TCP/IP协议实现的是卖家联系外卖员送外卖这个过程, 但是两端还要对数据进行加工或者使用, 所以我们还需要一层协议, 这个协议不必在意数据传输的细节, 而是关心应用的细节.
这层协议就叫做应用层协议, 而应用是有不同场景的,所以应用层的协议是具有很多种类的, 其中这类协议中的HTTP就是这一类http协议的佼佼者.
http协议工作过程
例如我们在浏览器中搜索一个网址, 此时浏览器接收到这个HTTP请求,就会通过各种路由选择传输给对方的服务器, 经过对方服务器的处理之后, 服务器就会返回一个http响应:
HTTP的格式
http是一个文本格式的协议,可以通过chrome开发者工具或者Fiddler抓包,分析HTTP请求/响应的细节
抓包工具的使用(Fiddler)
使用Fiddler为例子, 下载链接: 显示如下官网页面
选择Fiddler Classic进行下载.
打开Fiddler:
选择Tools -> option:
选择HTTPS, 并将其全部勾选:
注意: 勾选的时候会弹出一个弹窗,此时选择"yes", 否则就只能重装Fiddler了
抓包工具原理
浏览器访问baidu.com的时候, 就会把HTTP请求先发送给Fiddler, Fiddler再把请求转发给百度的服务器, 搜狗返回数据的时候, Fiddler就会拿到返回的数据, 再将其交给浏览器.
因此Fiddler对于浏览器和百度服务器之间交互的数据细节, 都是非常清楚的.
抓包的结果
以访问百度的主页为例子:
首先我们清空Fiddler的内容(ctrl + A + DELETE):
然后我们访问百度的主页, Fiddler就会自动抓取:
可以看见里面有很多颜色的表示, 具体含义如下:
'
HTTP请求
我们点开一个蓝色的HTTP的文件, 选择raw查看原始报文:
点击view in notepad就会在记事本中打开 .
解释如下:
- 首行: [方法] + [url] + [版本]
- Header: 请求的属性, 为冒号分割的键值对, 每组属性直接使用'\n'来分隔, 遇到空行表示Header部分结束
- Body: 空行后面的内容, Body允许使用空字符串, 如果Body存在, 则header中会有Content-Length属性来表示Body的长度.
HTTP响应
解释如下:
- 首行: [版本号] + [状态码] + [状态码解释]
- Header: 请求的属性, 为冒号分割的键值对, 每组属性直接使用'\n'来分隔, 遇到空行表示Header部分结束
- Body: 空行后面的内容, Body允许使用空字符串, 如果Body存在, 则header中会有Content-Length属性来表示Body的长度.
协议格式总结
HTTP请求
URL
URL基本格式
我们平时说的网址, 其实就是说的URL, 也就是统一资源定位符, 英文全称Uniform Resource Locator.
互联网上每一个文件都有唯一的URL, 他包含的信息指出文件的位置, 以及浏览器应该怎么处理他.
URL详细规则由因特网标准rfc1738进行约定.
关于 URL encode
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
一个中文字符由 UTF-8 或者 GBK 这样的编码方式构成, 虽然在 URL 中没有特殊含义, 但是仍然需要进行转义. 否则浏览器可能把 UTF-8/GBK 编码中的某个字节当做 URL 中的特殊符号.
转义的规则如下: 将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式:
方法
方法, 也就是HTTP请求的首行中的类似于GET和POST等字眼:
下面我们介绍几个最常用的方法, 他们使用的频率站全部方法的90%左右,
GET
一般大部分请求都是Get, GET是http最长用的方法, 常用于获取服务器上的某个资源.在浏览器中直接输入URL,此时浏览器就会发送一个get请求,另外,HTML中的link, img, script等标签,也会触发get请求.
get请求的特点:
- 首行的第一部分为GET
- URL的query string可以为空,也可以不为空
- header部分有若干个键值对结构
- bofy部分为空
关于get请求的URL长度问题:
其实网上描述的get请求最长1024kb这样的说法是错误的,HTTP协议由RFC2616标准定义, 标准中明确定义对URL的长度没有任何限制, 时间URL的长度取决于浏览器的实现, 和HTTP服务器端的实现, 在浏览器端, 不同的浏览器最大长度是不同的, 但是现代浏览器支持的长度一般很长,在服务器端, 一般这个长度是可以配置的.
POST
POST 方法也是一种常见的方法. 多用于提交用户输入的数据给服务器(例如登陆页面).
通过 HTML 中的 form 标签可以构造 POST 请求, 或者使用 JavaScript 的 ajax 也可以构造 POST 请求.
使用 Fiddler 观察 POST 方法:
在某登录系统中:输入用户名, 密码, 验证码之后, 点击登陆, 就可以看到 POST 请求:
POST https://xxxxx/login HTTP/1.1
Host: v.bitedu.vip
Connection: keep-alive
Content-Length: 105
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/91.0.4472.77 Safari/537.36
Access-Control-Allow-Methods: PUT,POST,GET,DELETE,OPTIONS
Content-Type: application/json;charset=UTF-8
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Access-Control-Allow-Headers: Content-Type, Content-Length, Authorization,
Accept, X-Requested-With , yourHeaderFeild
Origin: https://v.bitedu.vip
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://v.bitedu.vip/login
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: username=123456789; rememberMe=true
{"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05ccde64b16
a861fa2bddfdcd15"}
一般什么时候能看到POST?
- 登录
- 上传文件
post请求的特点:
- 首行的第一部分为POST
- URL的query string 一般为空(也可以不为空)
- header部分有若干个键值对结构
- body部分一般补位空, body内的数据格式通过header中的content-Type来指定,body的长度有header中的Content-Length指定
GET个POST的区别
get / post 表示的是不同的语义, 但是实际上也并非需要严格遵守, http的语义, 只是一种建议, 程序员使用的时候也不一定非得遵守,对于body有没有的问题, 也不是绝对的, get也可能有body, post也可能没有body, 但是这都是少见的.
那这两有啥区别? 本质上是没有区别的, 使用get的场景, 替换成post一般也可以使用, 使用post的场景换成get也可以.
但是二者还是存在使用上的区别的:
- get习惯上用来表示获取数据, 而post用来表示提交数据
- get一般没有body, 需要携带数据则需要放到URL中, post一般有body
- get请求通常会设计成幂等的, post则无要求
- get可缓存, post不能
- get可以被浏览器搜藏, post不能
幂等
幂等是一种学术用于, 也就是如果输入是一定的, 那么得到的输出也是一定的, 这种情况就是幂等的.
幂等在服务器开发是很关键的, 因为设计成幂等之后就可以设计缓存了, 例如我需要知道5的阶乘是多少, 那么我将这个请求发送给服务器, 服务器计算得到的结果为120后, 先缓存这个结果然后再把结果响应给我们, 下次有人去问5!是多少的时候, 他就会直接回答是120, 这就有点类似于我们的乘法口诀表,当别人问我们9*9是多少的时候, 我们大脑中已经缓存了9*9的结果, 也就是81此时就直接使用不需要计算, 这也就节约了计算资源.
我们得到结果之后, 也可以吧计算结果保存下来, 这样下次再遇到需要计算5!的请求,我们就不必要发送给服务器计算, 直接那结果就行.
header
header的格式就是键值对的结构,每一个键值对占一行, 键值对之间使用分号分割.
Host
表示服务器主机的地址和端口.
Content-Length
表示body中的数据的长度
Content-Type
表示请求的body中的数据格式, 常见选项如下:
- application/x-www-form-urlencoded:form 表单提交的数据格式, 此时body格式如下:
title=test&content=hello
- multipart/form-data: form 表单提交的数据格式(在form标签中加上,enctyped="multipart/form-data"). 通常用于提交图片,文件, body格式如下
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
- application/json: 数据格式为json格式, body的格式如下:
{"username":"123456789","password":"xxxx","code":"jjjss"}
User-Agent
表示浏览器/操作系统的属性, 形如:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/91.0.4472.77 Safari/537.36
其中:
- 其中 Windows NT 10.0; Win64; x64 表示操作系统信息
- AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 表示浏览器信
息.
Referer
表示这个页面是从哪个页面跳转过来的.
如果直接在浏览器中输入URL, 或者直接通过收藏夹访问页面时是没有 Referer 的
body
body的格式和header中的Content-Type 密切相关, 罗列三种常见的情况
①application/x-wwwx-form-urlencoded
抓取码云上传头像的请求:
POST https://gitee.com/profile/upload_portrait_with_base64 HTTP/1.1 Host: gitee.com Connection: keep-alive Content-Length: 107389 sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91" Accept: */* X-CSRF-Token: 6ROfZGr4Y7Qx8td1TuKCnrG8gbODLCSUqUBZSw2b+ac= X-Requested-With: XMLHttpRequest sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Origin: https://gitee.com Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://gitee.com/HGtz2222 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: oschina_new_user=false; user_locale=zh-CN; yp_riddler_id=1ce4a551-a160- 4358-aa73-472762c79dc0; visit-gitee--2021-05-06%2010%3A12%3A24%20%2B0800=1; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22726826%22%2C%22first_id%22%3 A%22175869ba5888b6-0ea2311dc53295-303464-2073600- 175869ba5899ac%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E 7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6% 9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%2 4latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%22175869ba5888b6- 0ea2311dc53295-303464-2073600-175869ba5899ac%22%7D; remote_way=svn; tz=Asia%2FShanghai; Hm_lvt_24f17767262929947cc3631f99bfd274=1622637014,1622712683,1622863899,1623298 442; gitee_user=true; Hm_lpvt_24f17767262929947cc3631f99bfd274=1623298560; giteesessionn=c0hXQ0I5SjR1bWg5M01IR3RYS3hLT0RhelN1aFVuMExKdEdSSmRaQWIwRy9QWFUwV0thdzV1alIzYj RaOU9ZeDdkZEJZK2RtTVRNeTNFRHNYVW9ha2hEcWJyclIwS1NVRG1EL0xxTmJXSGxvSzh3c28zOHBia1 pIOFQrU3RYeWE0bE13S09DTm5MZWZ5WW5WUVFpSzFiMGFWbHRDQ0xRakc1Um5yY21HQllqeUpNLzBvZF gxbHVhN09uK2h1VVVmRHZkS3BmVGEwcDhyNjJVb1p0RFRLY0VOem5vNEEvd0FuYzJJYlhZcGlyenZQc3 dSbXBNUWI3UUwrRDBrV2N0UHZRdjFBUXF5b0Y0L1Vrd09pQVBKNkdjZmY5cHlDTCtMWG4ya0tIaW5LcE tBTkw4cGFGVjhUQ0djMWhkOXI0bUFteUY4VW80RHl2T2Q2YmxwR1d3M3Rad1RhZWhhdnNiTTNrcE1RV2 NyZ1dYeDRoR0dpanh4bERNMTBuenB1NkgxLS16QUdJS3NlZG9mTVBtYlVlREppck1BPT0%3D- -898d1284181ca494918d29ac44f9a3a79d448a9b avatar=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAPgAAAD4CAYAAADB0Ss LAAAg......
抓包的结果比较长, 就没有全部贴出
②application/json
例如我们抓取某个登录页面的请求:
{"username":"123456789","password":"xxxx","code":"u58u","uuid":"9bd8e09ea27b48cd acc6a6bc41d9f462"}
③multipart/form-data
HTTP响应
状态码
- 200 OK : 表示访问成功
- 404 Not Found : 没有找到资源
- 403 Forbidden : 表示被拒绝访问, 没有特定的权限
- 405 Method Not Allowed : 服务器不支持当前的方法
- 500 Internal Server Error : 服务器内部错误
- 504 Gateway Timeout : 服务器负载比较大的时候 就可能出现超时的情况
- 302 Move temporary : 临时重定向
- 301 Moved Permanently : 永久重定向, 后续的请求都是指定搞得新地址
状态码小结:
状态码 | 类别 | 原因 |
1xx | Informatioanl (信息性状态码) | 接收的请求正在处理 |
2xx | Success(成功状态码) | 请求正常处理完毕 |
3xx | Redirection (重定向状态码) | 需要进行附加操作完成请求 |
4xx | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5xx | Server Error( 服务器错误状态码) | 服务器处理请求出错 |
header
响应报头header 的基本格式和请求报头 格式基本一致
类似于Content-Type, Content-Length 等属性的含义也和请求中的含义一致.
对于Content-Type 常见取值有以下几种:
- text/html : body 数据格式为 HTML
- text/css : body 数据格式为CSS
- application/javascript : body的数据格式为javascript
- applicationj/json : body的数据格式是JSON
body
也就是header里面对应的Content-Type 对应的内容
text/html
Server: nginx/1.17.3 Date: Thu, 10 Jun 2021 07:25:09 GMT Content-Type: text/html; charset=utf-8 Last-Modified: Thu, 13 May 2021 09:01:26 GMT Connection: keep-alive ETag: W/"609ceae6-3206" Content-Length: 12806 <!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,userscalable=no"><link rel=icon href=/favicon.ico><title id=bodyTitle>比特教务管理系统 </title><link href=https://cdn.bootcss.com/jquerydatetimepicker/2.5.20/jquery.datetimepicker.css rel=stylesheet><script src=https://cdn.bootcss.com/highlight.js/9.1.0/highlight.min.js></script><script src=https://cdn.bootcss.com/highlightjs-line-numbers.js/2.5.0/highlightjs-linenumbers.min.js></script><style>html, body, #app { height: 100%; margin: 0px; padding: 0px; } .chromeframe { margin: 0.2em 0; background: #ccc; color: #000; padding: 0.2em 0; } #loader-wrapper { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 999999; }
text/css
HTTP/1.1 200 OK Server: nginx/1.17.3 Date: Thu, 10 Jun 2021 07:25:09 GMT Content-Type: text/css Last-Modified: Thu, 13 May 2021 09:01:26 GMT Connection: keep-alive ETag: W/"609ceae6-3cfbe" Content-Length: 249790 @font-face{font-family:element-icons;src:url(../../static/fonts/elementicons.535877f5.woff) format("woff"),url(../../static/fonts/elementicons.732389de.ttf) format("truetype");font-weight:400;font-style:normal} [class*=" el-icon-"], ......
application/javascript
HTTP/1.1 200 OK Server: nginx/1.17.3 Date: Thu, 10 Jun 2021 07:25:09 GMT Content-Type: application/javascript; charset=utf-8 Last-Modified: Thu, 13 May 2021 09:01:26 GMT Connection: keep-alive ETag: W/"609ceae6-427d4" Content-Length: 272340 (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["app"], {0:function(t,e,n){t.exports=n("56d7")},"00b3":function(t,e,n){}," ......
applicationj/json
HTTP/1.1 200 Server: nginx/1.17.3 Date: Thu, 10 Jun 2021 07:25:10 GMT Content-Type: application/json;charset=UTF-8 Connection: keep-alive X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 vary: accept-encoding Content-Length: 12268 {"msg":"操作成功","code":200,"permissions":[] }
通过form表单构造HTTP请求
form 是HTML里面常用的标签, 可以用于给服务器发送get 或者POST请求"::"
此处需要注意的是不要把form 拼写成了 from
form 发送get请求
form 的重要参数
- action : 构造的HTTP请求的 URL 是什么
- method : 够早的 HTTP请求的方法是get 还是 Post ( form 表单只支持get和 post)
input 的重要参数:
- type : 表示 输入框的类型.... text 表示 文本, password 表示密码, submit 表示提交按钮
- name : 表示构造出的 HTTP请求的 query String 的 key, querystring 的value 就是输入框的用户输入的内容
- value : input 标签的值, 对于 type' 为submit 的类型来说 , value 就对应了按键上显示的文本
例如, 下面是一个form 表单::
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>test</title> </head> <body> <form action="http://abcdef.com/myPath" method="get"> <input type="text" name="userId"> <input type="text" name="classId"> <input type="submit" value="提交"> </form> </body> </html>
下面是发送出去的HTTP请求:
GET http://abcdef.com/myPath?userId=100&classId=200 HTTP/1.1 Host: abcdef.com Proxy-Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
GET http://abcdef.com/myPath?userId=100&classId=200 HTTP/1.1
Host: abcdef.com
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/91.0.4472.114 Safari/537.36
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag
e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
他们是一一对应的::
form 发送post请求
发送post请求只需要把form表单里面的 method修改为post:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>test</title> </head> <body> <form action="http://abcdef.com/myPath" method="post"> <input type="text" name="userId"> <input type="text" name="classId"> <input type="submit" value="提交"> </form> </body> </html>
构造的 HTTP 请求
POST http://abcdef.com/myPath HTTP/1.1 Host: abcdef.com Proxy-Connection: keep-alive Content-Length: 22 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: null Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 userId=100&classId=200
主要的区别:
- method 从get变成了 get了
- 数据从queryString 移动到了 body中去了
使用form 表单还可以提交文件
通过ajax 构造http请求
从前端角度, 除了浏览器地址栏能构造 GET 请求, form 表单能构造 GET 和 POST 之外, 还可以通过 ajax的方式来构造 HTTP 请求. 并且功能更强大....
ajax 全称 Asynchronous Javascript And XML, 是 2005 年提出的一种 JavaScript 给服务器发送HTTP 请求的方式.
特点是--->> 可以不需要 刷新页面/页面跳转 就能进行数据传输
发送get请求
创建 test.html . 在 script标签中编写如下代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>test</title> </head> <body> <script> // 1. 创建 XMLHttpRequest 对象 let httpRequest = new XMLHttpRequest(); // 2. 默认异步处理响应. 需要挂在处理响应的回调函数 httpRequest.onreadystatechange = function () { // readState 表示当前的状态. // 0: 请求未初始化 // 1: 服务器连接已建立 // 2: 请求已接收 // 3: 请求处理中 // 4: 请求已完成,且响应已就绪 if (httpRequest.readyState == 4) { // status 属性获取 HTTP 响应状态码 console.log(httpRequest.status); // responseText 属性获取 HTTP 响应 body console.log(httpRequest.responseText); } } httpRequest.open('GET','http://42.192.83.143:8080/AjaxMockServer/info'); httpRequest.send; </script> </body> </html>
其中:
- onreadystatechange : 存储函数, 每当readyState 属性改变的时候, 就会调用该函数
- readyState : 存有XMLHttpRequest 的状态, 从0 ~4 变化
- status : 200: OK, 404: 未找到资源.......
发送 POST 请求
对于 POST 请求, 需要设置 body 的内容
1. 先使用 setRequestHeader 设置 Content-Type
2. 再通过 send 的参数设置 body 内容
发送 application/x-www-form-urlencoded 数据 (数据格式同 form 的 post)
// 1. 创建 XMLHttpRequest 对象 let httpRequest = new XMLHttpRequest(); // 2. 默认异步处理响应. 需要挂在处理响应的回调函数. httpRequest.onreadystatechange = function () { // readState 表示当前的状态. // 0: 请求未初始化 // 1: 服务器连接已建立 // 2: 请求已接收 // 3: 请求处理中 // 4: 请求已完成,且响应已就绪 if (httpRequest.readyState == 4) { // status 属性获取 HTTP 响应状态码 console.log(httpRequest.status); // responseText 属性获取 HTTP 响应 body console.log(httpRequest.responseText); } } // 3. 调用 open 方法设置要访问的 url httpRequest.open('POST', 'http://42.192.83.143:8080/AjaxMockServer/info'); // 4. 调用 setRequestHeader 设置请求头 httpRequest.setRequestHeader('Content-Type', 'application/x-www-formurlencoded'); // 5. 调用 send 方法发送 http 请求 httpRequest.send('name=zhangsan&age=18');
发送 application/json 数据
// 4. 调用 setRequestHeader 设置请求头 httpRequest.setRequestHeader('Content-Type', 'application/json'); // 5. 调用 send 方法发送 http 请求 httpRequest.send(JSON.stringify({ name: 'zhangsan', age: 18 }));
封装 ajax 方法
原生的 XMLHTTPRequest 类使用并不方便. 我们可以在这个基础上进行简单封装
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>test</title> </head> <body> <script> // 参数 args 是一个 JS 对象, 里面包含了以下属性 // method: 请求方法 // url: 请求路径 // body: 请求的正文数据 // contentType: 请求正文的格式 // callback: 处理响应的回调函数, 有两个参数, 响应正文和响应的状态码 function ajax(args) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { // 0: 请求未初始化 // 1: 服务器连接已建立 // 2: 请求已接收 // 3: 请求处理中 // 4: 请求已完成,且响应已就绪 if (xhr.readyState == 4) { args.callback(xhr.responseText, xhr.status) } } xhr.open(args.method, args.url); if (args.contentType) { xhr.setRequestHeader('Content-type', args.contentType); } if (args.body) { xhr.send(args.body); } else { xhr.send(); } } // 调用该函数 ajax({ method: 'get', url: '/info', callback: function (body, status) { console.log(status); console.log(body); } }); </script> </body> </html>