网络原理10 - HTTP完
上一篇文章我们详细了解了HTTP请求,本篇文章我们来简单认识下HTTP响应中的状态码,并尝试使用第三方工具来构造一个HTTP请求。
认识状态码
状态码表示返回的响应结果如何(访问成功还是失败,失败的话是啥原因)。
HTTP中的状态码都是标准文档约定好的:
上面的状态码不需要全部记住,只需要记住常见的几个即可:
200 OK
这是最常见的状态码,表示访问成功。
404 Not Found
表示访问资源没有找到。浏览器中输入一个URL,就可以访问对方服务器上的一个具体资源。如果这个资源不存在,那么就会出现404 NotFound,例如:输入一个https://www.bilibili.com/abcde.html,此时就是尝试访问bilibili的abcde.html这个资源(这个资源并不存在)。
此时就会看到这样的页面(为了符合动漫视频软件的特点,bilibili使用html设计了一个好康的页面,并不是所有404都是这样):
百度的404就非常简洁明了:
403 Forbidden
表示请求资源没有权限访问。(类似于JavaSE中的封装)
例如:打开一个码云的私有仓库就会出现403:您的访问受限 (403) (gitee.com)
405 Method Not Allowed
你当前的设备不支持这个方法。
你的服务器只支持GET请求,但是你发了个POST,就会出现405 Method Not Allowed(这里无法进行演示,需要学习Spring后才可能出现,这里我们了解即可)。
500 Internal Sever Error
服务器挂了。
504 Gateway TimeOut
访问服务器超时,可能是网络连接断了,也可能是服务器挂了。
302 Move temporarily
临时重定向。
重定向:
类似于我们换手机之后的“呼叫转移”功能:
比如:我们原来的电话号码是111-1234-1235,后来换了一个新号码111-1234-1236,此时我难道要给我的盆友一个个打电话告知他们我的新号码吗?
此时,我们可以去运营商哪里办理一个“呼叫转移”的业务,其他人拨打111-1234-1235的时候就会自动跳转到111-1234-1236上。
那么什么时候会出现临时重定向呢?
登录的时候,我们可以登录一个软件,然后使用Fiddler进行抓包查看结果:
这个就是我们登陆软件返回的响应,状态码显示为:302。
查看响应报文:
这里面的header部分会包含一个Location字段,表示要跳转的那个页面。
301 Moved Permanently
永久重定向,当浏览器收到状态码为301的响应的时候,后续的请求都会被自动改成新地址,此时就不必再多跳转一次了(可以被浏览器缓存,302不太方便被浏览器缓存)。
在301的响应报文中,同样会有一个Location,描述了重定向的位置是在哪里。
418 I am a teaport
一个特殊的状态码,没有实际的含义,I am a teaport 我是个茶壶(我是个杯具)。
这是设计HTTP协议的大佬开玩笑 -- "彩蛋"。
状态码小结:
认识响应“报头”
响应报头的基本格式和请求报头的格式基本一致。Content-Type,Content-Length等属性的含义和作用也和请求中的一致。
Content - Type
响应中的Content-Type常见取值:
text/html:body数据格式是HTML
text/css:body数据格式是CSS
application/javascript:body数据格式是Javascript
application/json:body数据格式是JSON
构造HTTP请求
通过第三方工具进行构造
使用postman就可以构造HTTP请求。
postman下载
在必应上直接搜索postman(这里需要注意下载的URL!!!)
点击这里进行下载:
下载完之后,需要输入自己的邮箱进行注册(这里过程就省略了~)
postman的使用
安装注册完毕后,点击Workspaces,再点击CreateWorkspace。
点击next
输入Name之后,Create即可。
点击+号就可以开始构造HTTP请求了:
这是一些基本功能介绍:
请求构造
自定义之后,点击Send。
结果如下:
另外,可以点击这里生成Java版本的HTTP请求:
再点击复制,然后粘贴到我们的代码中即可。
通过代码来构造HTTP请求
发送HTTP请求,本质上就是按照HTTP格式往TCP的SeverSocket中写入一个字符串;接收HTTP响应,本质上就是从TCP的Socket中读取一个字符串,再按照HTTP的格式进行解析。
我们可以基于Socket,构造出一个简单的HTTP客户端程序,用来发送各种类型的HTTP请求。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;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("www.bilibili.com",80);String resp = httpClient.get("/index.html");System.out.println(resp);String postResp = httpClient.post("/index.html","this is a body");System.out.println(postResp);}
}