目录
1) application/x-www-form-urlencoded
发送 application/x-www-form-urlencoded 数据 (数据格式同 form 的 post)
什么是HTTP协议
HTTP (
全称为
"
超文本传输协议
")
是一种应用非常广泛的
应用层协议
.
- 应用层协议:1.基于某个特定的传输层协议之上 2.用于描述业务 3.非操作系统代码
HTTP
往往是基于传输层的
TCP
协议实现的
. (HTTP1.0, HTTP1.1, HTTP2.0
均为
TCP, HTTP3
基于
UDP 实现)
我们平时打开一个网站
,
就是通过
HTTP
协议来传输数据的
当我们在浏览器中输入一个 搜狗搜索的
"
网址
" (URL)
时
,
浏览器就给搜狗的服务器发送了一个
HTTP
请 求,
搜狗的服务器返回了一个
HTTP
响应
.
这个响应结果被浏览器解析之后
,
就展示成我们看到的页面内容
. (
这个过程中浏览器可能会给服务器发送 多个 HTTP
请求
,
服务器会对应返回多个响应
,
这些响应里就包含了页面
HTML, CSS, JavaScript,
图片
,
字 体等信息)
所谓
"
超文本
"
的含义
,
就是传输的内容不仅仅是文本
(
比如
html, css
这个就是文本
),
还可以是一些
其他的资源
,
比如图片
,
视频
,
音频等二进制的数据
.
理解 "应用层协议"
我们已经学过
TCP/IP
,
已经知道目前数据能从客户端进程经过路径选择跨网络传送到服务器端进程 [ IP+Port
].
可是,仅仅把数据从
A
点传送到
B
点就完了吗?
这就好比,在淘宝上买了一部手机,卖家
[
客户端
]
把手机通过顺丰
[
传送
+
路径选择
]
送到买家
[
服务器
]
手里就完了吗?
当然不是,买家还要使用这款产品,还要在使用之后,给卖家打分评论。
所以,我们把数据从
A
端传送到
B
端,
TCP/IP
解决的是顺丰的功能,而两端还要对数据进行加工处理或 者使用,所以我们还需要一层协议,不关心通信细节,关心应用细节!
这层协议叫做应用层协议。而应用是有不同的场景的,所以应用层协议是有不同种类的,其中经典协议 之一的HTTP就是其中的佼佼者
.
再回到我们刚刚说的买手机的例子,顺丰相当于
TCP/IP
的功能,那么买回来的手机都附带了说明
书【产品介绍,使用介绍,注意事项等】,而该说明书指导用户该如何使用手机【虽然我们都不
看,但是父母辈有部分是有看说明书的习惯的:)】,此时的说明书可以理解为用户层协议
理解 HTTP 协议的工作过程
当我们在浏览器中输入一个
"
网址
",
此时浏览器就会给对应的服务器发送一个
HTTP
请求
.
对方服务器收到这个请求之后,
经过计算处理
,
就会返回一个
HTTP
响应
事实上
,
当我们访问一个网站的时候
,
可能涉及不止一次的
HTTP
请求
/
响应 的交互过程
.
可以通过
chrome
的开发者工具观察到这个详细的过程
.
通过
F12
打开
chrome
的开发者工具
,
切换到
Network
标签页
.
然后刷新页面即可看到如下图效
果
.
每一条记录都是一次
HTTP
请求
/
响应
HTTP 协议格式
HTTP
是一个文本格式的协议
.
可以通过
Chrome
开发者工具或者
Fiddler
抓包
,
分析
HTTP
请求
/
响应的细节
HTTP 请求 (Request)
认识 URL
URL 基本格式
平时我们俗称的
"
网址
"
其实就是说的
URL (Uniform Resource Locator
统一资源定位符
).
互联网上的每个文件都有一个唯一的
URL
,它包含的信息指出文件的位置以及浏览器应该怎么处理它
. URL 的详细规则由 因特网标准
RFC1738
进行了约定。
(
https://datatracker.ietf.org/doc/html/rfc1738
)
一个具体的 URL:
可以看到
,
在这个
URL
中有些信息被省略了
.
- https : 协议方案名. 常见的有 http 和 https, 也有其他的类型. (例如访问 mysql 时用的 jdbc:mysql )
- user:pass : 登陆信息. 现在的网站进行身份认证一般不再通过 URL 进行了. 一般都会省略
- v.bitedu.vip : 服务器地址. 此处是一个 "域名", 域名会通过 DNS 系统解析成一个具体的 IP 地址. (通过 ping 命令可以看到, v.bitedu.vip 的真实 IP 地址为 118.24.113.28 )
- 端口号: 上面的 URL 中端口号被省略了. 当端口号省略的时候, 浏览器会根据协议类型自动决定使用哪个端口. 例如 http 协议默认使用 80 端口, https 协议默认使用 443 端口.
- /personInf/student : 带层次的文件路径.
- userId=10000&classId=100 : 查询字符串(query string). 用问号开头,本质是一个键值对结构. 键值对之间使用 & 分隔. 键和值之间使用 = 分隔.
- 片段标识: 此 URL 中省略了片段标识. 片段标识主要用于页面内跳转.用井号开头. (例如 Vue 官方文档: https://c n.vuejs.org/v2/guide/#%E8%B5%B7%E6%AD%A5, 通过不同的片段标识跳转到文档的不同章节)
使用
ping
命令查看域名对应的
IP
地址
.
1.
在开始菜单中输入
cmd
,
打开
命令提示符
2.
在
cmd
中输入
ping v.bitedu.vip
,
即可看到域名解析的结果
.
PS:
有的电脑上
ping
命令会报错
ping
不是内部或外部命令,也不是可运行的程序或批处理文件
.
这种情况是因为有的 Windows10
默认没有启用
ping
命令
.
百度搜索
windows10
启用
ping
即可
关于
query string
query string
中的内容是键值对结构
.
其中的
key
和
value
的取值和个数
,
完全都是程序猿自己约
定的
.
我们可以通过这样的方式来自定制传输我们需要的信息给服务器.
URL
中的可省略部分
- 协议名: 可以省略, 省略后默认为 http://
- ip 地址 / 域名: 在 HTML 中可以省略(比如 img, link, script, a 标签的 src 或者 href 属性). 省
- 略后表示服务器的 ip / 域名与当前 HTML 所属的 ip / 域名一致.
- 端口号: 可以省略. 省略后如果是 http 协议, 端口号自动设为 80; 如果是 https 协议, 端口号自
- 动设为 443.
- 带层次的文件路径: 可以省略. 省略后相当于 / . 有些服务器会在发现 / 路径的时候自动访问
- /index.html
- 查询字符串: 可以省略
- 片段标识: 可以省略
关于 URL encode
像
/ ? :
等这样的字符
,
已经被
url
当做特殊意义理解了
.
因此这些字符不能随意出现
.
比如
,
某个参数中需要带有这些特殊字符
,
就必须先对特殊字符进行转义
.
一个中文字符由
UTF-8
或者
GBK
这样的编码方式构成
,
虽然在
URL
中没有特殊含义
,
但是仍然需
要进行转义
.
否则浏览器可能把
UTF-8/GBK
编码中的某个字节当做
URL
中的特殊符号
.
转义的规则如下
:
将需要转码的字符转为
16
进制,然后从右到左,取
4
位
(
不足
4
位直接处理
)
,每
2
位做一
位,前面加上
%
,编码成
%XY
格式
例如
:
"+"
被转义成了
"%2B"
urldecode
就是
urlencode
的逆过程
;
认识 "方法" (method)
1. GET 方法
GET
是最常用的
HTTP
方法
.
常用于获取服务器上的某个资源
.
在浏览器中直接输入
URL,
此时浏览器就会发送出一个
GET
请求
.
另外
, HTML
中的
link, img, script
等标签
,
也会触发
GET
请求
.
使用 Fiddler 观察 GET 请求
打开
Fiddler,
访问 搜狗主页
,
观察抓包结果
.
在上面的结果中可以看到:
GET
请求的特点
- 首行的第一部分为 GET
- URL 的 query string 可以为空, 也可以不为空.
- header 部分有若干个键值对结构.
- body 部分为空.
关于
GET
请求的
URL
长度问题
网上有些资料上描述
:
get
请求长度最多
1024kb
这样的说法是错误的
.
HTTP
协议由
RFC 2616
标准定义
,
标准原文中明确说明
: "Hypertext Transfer Protocol --
HTTP/1.1," does not specify any requirement for URL length.
没有对
URL
的长度有任何的限制
.
实际
URL
的长度取决于浏览器的实现和
HTTP
服务器端的实现
.
在浏览器端
,
不同的浏览器最大长
度是不同的
,
但是现代浏览器支持的长度一般都很长
;
在服务器端
,
一般这个长度是可以配置的
2. POST 方法
POST
方法也是一种常见的方法
.
多用于提交用户输入的数据给服务器
(
例如登陆页面
).
通过
HTML
中的
form
标签可以构造
POST
请求
,
或者使用
JavaScript
的
ajax
也可以构造
POST
请求
.
使用 Fiddler 观察 POST 方法
在比特教务系统的登陆页面
,
输入用户名
,
密码
,
验证码之后
,
点击登陆
,
就可以看到
POST
请求
.
POST 请求的特点
首行的第一部分为
POST
URL
的
query string
一般为空
(
也可以不为空
)
header
部分有若干个键值对结构
.
body
部分一般不为空
. body
内的数据格式通过
header
中的
Content
-
Type
指定
. body
的长度由
header
中的
Content
-
Length
指定
.
经典面试题
:
谈谈
GET
和
POST
的区别
语义不同
: GET
一般用于获取数据
, POST
一般用于提交数据
.
GET
的
body
一般为空
,
需要传递的数据通过
query string
传递
, POST
的
query string
一般
为空
,
需要传递的数据通过
body
传递
GET
请求一般是幂等的
, POST
请求一般是不幂等的
. (
如果多次请求得到的结果一样
,
就视为请
求是幂等的
).
GET
可以被缓存
, POST
不能被缓存
. (
这一点也是承接幂等性
).
补充说明
:
关于语义
: GET
完全可以用于提交数据
, POST
也完全可以用于获取数据
.
关于幂等性
:
标准建议
GET
实现为幂等的
.
实际开发中
GET
也不必完全遵守这个规则
(
主流网
站都有
"
猜你喜欢
"
功能
,
会根据用户的历史行为实时更新现有的结果
.
关于安全性
:
有些资料上说
"POST
比
GET
请安全
".
这样的说法是不科学的
.
是否安全取决于
前端在传输密码等敏感信息时是否进行加密
,
和
GET POST
无关
.
关于传输数据量
:
有的资料上说
"GET
传输的数据量小
, POST
传输数据量大
".
这个也是不科学
的
,
标准没有规定
GET
的
URL
的长度
,
也没有规定
POST
的
body
的长度
.
传输数据量多少
,
完
全取决于不同浏览器和不同服务器之间的实现区别
.
关于传输数据类型
:
有的资料上说
"GET
只能传输文本数据
, POST
可以传输二进制数据
".
这个
也是不科学的
. GET
的
query string
虽然无法直接传输二进制数据
,
但是可以针对二进制数据
进行
url encode.
3. 其他方法
- PUT 与 POST 相似,只是具有幂等特性,一般用于更新
- DELETE 删除服务器指定资源
- OPTIONS 返回服务器所支持的请求方法
- HEAD 类似于GET,只不过响应体不返回,只返回响应头
- TRACE 回显服务器端收到的请求,测试的时候会用到这个
- CONNECT 预留,暂无使用
这些方法的
HTTP
请求可以使用
ajax
来构造
. (
也可以通过一些第三方工具
)
任何一个能进行网络编程的语言都可以构造
HTTP
请求
.
本质上就是通过
TCP socket
写入一个符
合
HTTP
协议规则的字符串
.
认识请求 "报头" (header)
header
的整体的格式也是
"
键值对
"
结构
.
每个键值对占一行
.
键和值之间使用分号分割
.
报头的种类有很多
,
此处仅介绍几个常见的
.
Host
表示服务器主机的地址和端口
.
Content-Length
表示
body
中的数据长度
.
Content-Type
表示请求的
body
中的数据格式
.
常见选项
:
application/x-www-form-urlencoded: form
表单提交的数据格式
.
此时
body
的格式形如
:
multipart/form-data: form
表单提交的数据格式
(
在
form
标签中加上
enctyped="multipart/form
-
data"
.
通常用于提交图片
/
文件
. body
格式形如
:
application/json: 数据为 json 格式. body 格式形如:
User-Agent (简称 UA)
表示浏览器
/
操作系统的属性
.
形如
其中
Windows NT 10.0
;
Win64
;
x64
表示操作系统信息
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36
表示浏览器信
息
Referer
表示这个页面是从哪个页面跳转过来的
.
形如
如果直接在浏览器中输入
URL,
或者直接通过收藏夹访问页面时是没有
Referer
的
.
Cookie
Cookie
中存储了一个字符串
,
这个数据可能是客户端
(
网页
)
自行通过
JS
写入的
,
也可能来自于服务器
(
服
务器在
HTTP
响应的
header
中通过
Set-Cookie
字段给浏览器返回数据
).
往往可以通过这个字段实现
"
身份标识
"
的功能
.
每个不同的域名下都可以有不同的
Cookie,
不同网站之间的
Cookie
并不冲突
.
可以通过抓包观察页面登陆的过程
(
以码云为例
):
1) 清除之前的 cookie
为了方便观察
,
先清除掉之前登陆的
cookie
在码云页面上
,
点击
url
左侧的图标
,
选择
Cookie
然后移除已经存在的 Cookie
2) 登陆操作
登陆请求
登陆响应
可以看到
,
响应中包含了
3
个
Set-Cookie
属性
.
其中我们重点关注第三个
.
里面包含了一个
gitee
-
session
-
n
这样的属性
,
属性值是一串很长的加
密之后的信息
.
这个信息就是用户当前登陆的身份标识
.
也称为
"
令牌
(token)"
3) 访问其他页面
登陆成功之后
,
此时可以看到后续访问码云的其他页面
(
比如个人主页
),
请求中就都会带着刚才获取到的Cookie 信息
请求你中的
Cookie
字段也包含了一个
gitee
-
session
-
n
属性
,
里面的值和刚才服务器返回的值相
同
.
后续只要访问
gitee
这个网站
,
就会一直带着这个令牌
,
直到令牌过期
/
下次重新登陆
理解登陆过程
这个过程和去医院看病很相似
.
1.
到了医院先挂号
.
挂号时候需要提供身份证
,
同时得到了一张
"
就诊卡
",
这个就诊卡就相当于患
者的
"
令牌
".
2.
后续去各个科室进行检查
,
诊断
,
开药等操作
,
都不必再出示身份证了
,
只要凭就诊卡即可识别
出当前患者的身份
.
3.
看完病了之后
,
不想要就诊卡了
,
就可以注销这个卡
.
此时患者的身份和就诊卡的关联就销毁
了
. (
类似于网站的注销操作
)
4.
又来看病
,
可以办一张新的就诊卡
,
此时就得到了一个新的
"
令牌
"
认识请求 "正文" (body)
正文中的内容格式和
header
中的
Content-Type
密切相关
.
上面也罗列了三种常见的情况
.
下面可以通过抓包来观察这几种情况
:
1) application/x-www-form-urlencoded
抓取码云上传头像请求
2) multipart/form-data
抓取比特教务系统的
"
上传简历
"
功能
3) application/json
抓取比特教务系统的登陆页面
https://v.bitedu.vip/login
HTTP 响应详解
认识 "状态码" (status code)
状态码表示访问一个页面的结果
. (
是访问成功
,
还是失败
,
还是其他的一些情况
...).
以下为常见的状态码
.
200 OK
这是一个最常见的状态码
,
表示访问成功
.
抓包抓到的大部分结果都是
200
例如访问搜狗主页
注意: 在抓包观察响应数据的时候, 可能会看到压缩之后的数据, 形如
404 Not Found
没有找到资源
.
浏览器输入一个
URL,
目的就是为了访问对方服务器上的一个资源
.
如果这个
URL
标识的资源不存
在
,
那么就会出现
404
例如
,
在浏览器中输入
www.sogou.com/index.html
,
此时就在尝试访问
sogou
上的
/index.html
这个资源
.
如果输入正确
,
则可以正确访问到
.
但是如果输入错误
,
比如
www.sogou.com/index2.html
,
就会
看到
404
这样的响应
.
403 Forbidden
表示访问被拒绝
.
有的页面通常需要用户具有一定的权限才能访问
(
登陆后才能访问
).
如果用户没有登陆 直接访问,
就容易见到
403.
例如
:
查看码云的私有仓库
,
如果不登陆
,
就会出现
403.
参考链接
:
https://gitee.com/HGtz2222/bl
og_python
405 Method Not Allowed
前面我们已经学习了
HTTP
中所支持的方法
,
有
GET, POST, PUT, DELETE
等
.
但是对方的服务器不一定都支持所有的方法
(
或者不允许用户使用一些其他的方法
).
这种情况我们后面学习了
Servlet
再演示
.
500 Internal Server Error
服务器出现内部错误
.
一般是服务器的代码执行过程中遇到了一些特殊情况
(
服务器异常崩溃
)
会产生这个
状态码
.
咱们平时常用的网站很少会出现
500 (
但是偶尔也能看到
).
这种情况我们后面学习了
Servlet
再演示
.
504 Gateway Timeout
当服务器负载比较大的时候
,
服务器处理单条请求的时候消耗的时间就会很长
,
就可能会导致出现超时的
情况
.
这种情况在双十一等
"
秒杀
"
场景中容易出现
,
平时不太容易见到
.
302 Move temporarily
临时重定向
.
理解
"
重定向
"
就相当于手机号码中的
"
呼叫转移
"
功能
.
比如我本来的手机号是
186-1234-5678,
后来换了个新号码
135-1234-5678,
那么不需要让我的朋
友知道新号码
,
只要我去办理一个呼叫转移业务
,
其他人拨打
186-1234-5678 ,
就会自动转移到
135-1234-5678
上
.
在登陆页面中经常会见到
302.
用于实现登陆成功后自动跳转到主页
.
响应报文的
header
部分会包含一个
Location
字段
,
表示要跳转到哪个页面
.
例如
:
码云的登陆页面
https://gitee.com/login
抓包看到的响应结果
:
可以看到
header
中的
Location: https://gitee.com/HGtz2222
,
接下来浏览器就会自动发送
GET
请求
,
获取
https://gitee.com/HGtz2222
301 Moved Permanently
永久重定向
.
当浏览器收到这种响应时
,
后续的请求都会被自动改成新的地址
.
301
也是通过
Location
字段来表示要重定向到的新地址
.
状态码小结
认识响应 "报头" (header)
响应报头的基本格式和请求报头的格式基本一致
.
类似于
Content
-
Type
,
Content
-
Length
等属性的含义也和请求中的含义一致
.
Content-Type
响应中的
Content-Type
常见取值有以下几种
:
text/html
: body
数据格式是
HTML
text/css
: body
数据格式是
CSS
application/javascript
: body
数据格式是
JavaScript
application/json
: body
数据格式是
JSON
认识响应 "正文" (body)
正文的具体格式取决于
Content-Type.
观察上面几个抓包结果中的响应部分
.
1) text/html
2) text/css
3) application/javascript
4) application/json
通过 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. query string
的
value
就是输入框的用户
输入的内容
.
value: input
标签的值
.
对于
type
为
submit
类型来说
, value
就对应了按钮上显示的文本
.
<form action = "http://abcdef.com/myPath" method = "GET" ><input type = "text" name = "userId" ><input type = "text" name = "classId" ><input type = "submit" value = " 提交 " ></form>
构造的 HTTP 请求
体会 form 代码和 HTTP 请求之间的对应关系
- form 的 action 属性对应 HTTP 请求的 URL
- form 的 method 属性对应 HTTP 请求的方法
- input 的 name 属性对应 query string 的 key
- input 的 内容 对应 query string 的 value
form 发送 POST 请求
修改上面的代码
,
把
form
的
method
修改为
POST
<form action = "http://abcdef.com/myPath" method = "GET" ><input type = "text" name = "userId" ><input type = "text" name = "classId" ><input type = "submit" value = " 提交 " ></form>
构造的 HTTP 请求
主要的区别
:
method
从
GET
变成了
POST
数据从
query string
移动到了
body
中
.
使用
form
还可以提交文件
.
后面再介绍
.
通过 ajax 构造 HTTP 请求
从前端角度
,
除了浏览器地址栏能构造
GET
请求
, form
表单能构造
GET
和
POST
之外
,
还可以通过
ajax 的方式来构造 HTTP
请求
.
并且功能更强大
.
ajax
全称
A
synchronous
J
avascript
A
nd
X
ML,
是
2005
年提出的一种
JavaScript
给服务器发送
HTTP
请求的方式
.
特点是可以不需要 刷新页面
/
页面跳转 就能进行数据传输
.
在
JavaScript
中可以通过
ajax
的方式构造
HTTP
请求
.
注意
:
为了验证
ajax
的功能
,
需要提前准备好一份配套的服务器程序
发送 GET 请求
创建
test.html,
在
<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 响应 bodyconsole . log ( httpRequest . responseText );}}// 3. 调用 open 方法设置要访问的 urlhttpRequest . open ( 'GET' , 'http://42.192.83.143:8080/AjaxMockServer/info' );// 4. 调用 send 方法发送 http 请求httpRequest . send ();
注意
:
如果把
send
中的地址改成其他服务器的地址
(
比如
http://www.sogou.com/index.html
这
种
),
大概率是会出错的
.
错误形如
:
这个错误是因为
ajax
默认不能
"
跨域
",
也就是
"
百度下面的
html
中的
ajax
不能访问 搜狗 的内容
".
这样的设定也是完全合理的
.
如果想要强行进行跨域
,
则需要服务器进行配合
,
在服务器的响应中
"
允许跨域
"
才可以
.
浏览器和服务器交互过程
(
引入
ajax
后
):
在我们当前的例子中
, test.html
是通过本地文件的方式打开的
,
这个环节不涉及
HTTP
交互
.
后面我们把
test.html
放到
Tomcat
上
,
就会产生上面的效果了
发送 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 响应 bodyconsole . log ( httpRequest . responseText );}}// 3. 调用 open 方法设置要访问的 urlhttpRequest . 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
类使用并不方便
.
我们可以在这个基础上进行简单封装
.
// 参数 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 );}});
通过 Java socket 构造 HTTP 请求
所谓的
"
发送
HTTP
请求
",
本质上就是按照
HTTP
的格式往
TCP Socket
中写入一个字符串
.
所谓的
"
接受
HTTP
响应
",
本质上就是从
TCP Socket
中读取一个字符串
,
再按照
HTTP
的格式来解析
.
我们基于
Socket
的知识
,
完全可以构造出一个简单的
HTTP
客户端程序
,
用来发送各种类型的
HTTP
请求.
public class HttpClient {private Socket socket ;private String ip ;private int port ;public HttpClient ( String ip , int port ) throws IOException {this . ip = ip ;this . port = port ;socket = new Socket ( ip , port );}public String get ( String url ) throws IOException {StringBuilder request = new StringBuilder ();// 构造首行request . append ( "GET " + url + " HTTP/1.1\n" );// 构造 headerrequest . append ( "Host: " + ip + ":" + port + "\n" );// 构造 空行request . append ( "\n" );// 发送数据OutputStream outputStream = socket . getOutputStream ();outputStream . write ( request . toString (). getBytes ());// 读取响应数据InputStream inputStream = socket . getInputStream ();byte [] buffer = new byte [ 1024 * 1024 ];int n = inputStream . read ( buffer );return new String ( buffer , 0 , n , "utf-8" );}public String post ( String url , String body ) throws IOException {StringBuilder request = new StringBuilder ();// 构造首行request . append ( "POST " + url + " HTTP/1.1\n" );// 构造 headerrequest . append ( "Host: " + ip + ":" + port + "\n" );request . append ( "Content-Length: " + body . getBytes (). length + "\n" );request . append ( "Content-Type: text/plain\n" );// 构造 空行request . append ( "\n" );// 构造 bodyrequest . append ( body );// 发送数据OutputStream outputStream = socket . getOutputStream ();outputStream . write ( request . toString (). getBytes ());// 读取响应数据InputStream inputStream = socket . getInputStream ();byte [] buffer = new byte [ 1024 * 1024 ];int n = inputStream . read ( buffer );return new String ( buffer , 0 , n , "utf-8" );}public static void main ( String [] args ) throws IOException {HttpClient httpClient = new HttpClient ( "42.192.83.143" , 8080 );String getResp = httpClient . get ( "/AjaxMockServer/info" );System . out . println ( getResp );String postResp = httpClient . post ( "/AjaxMockServer/info" , "this isbody" );System . out . println ( postResp );}}
使用
Java
构造的
HTTP
客户端不再有
"
跨域
"
限制了
,
此时也可以用来获取其他服务器的数据了
.
跨域只是浏览器的行为
,
对于
ajax
有效
.
对于其他语言来说一般都和跨域无关
.
HttpClient httpClient = new HttpClient ( "www.sogou.com" , 80 );String resp = httpClient . get ( "/index.html" );System . out . println ( resp );// 此时可以获取到 搜狗主页 的 html