http协议
1 uri uniform resource identifider,统一资源标识符,用来唯一的标识一个资源
访问资源的命名机制 + 存放资源的主机名 + 资源本身的名称(路径) 着重强调于资源
URL locator, 一种具体的uri,他用来标示一个资源,还指明了如何locate这个资源。
协议 + IP + 资源的具体地址,强调的是路径
特点 : 简单快速 ,无连接(每次连接只处理一个请求,server 端 response 之后就会断开链接)
无状态:对已经处理的事务没有记忆的,后续如果继续处理网络请求的话,需要重新request。
Request Header
Referer
当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。比如从我主页上链接到一个朋友那里,他的服务器就能够从HTTP Referer中统计出每天有多少用户点击我主页上的链接访问他的网站。
If-Modified-Since
作用: 把浏览器端缓存页面的最后修改时间发送到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行对比。如果时间一致,那么返回304,客户端就直接使用本地缓存文件。如果时间不一致,就会返回200和新的文件内容。客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示在浏览器中.
例如:Mon, 17 Aug 2015 12:03:33 GMT
If-None-Match
作用: If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息。 当用户再次请求该资源时,将在HTTP Request 中加入If-None-Match信息(ETag的值)。如果服务器验证资源的ETag没有改变(该资源没有更新),将返回一个304状态告诉客户端使用本地缓存文件。否则将返回200状态和新的资源和Etag. 使用这样的机制将提高网站的性能
例如: If-None-Match: W/"3119-1437038474000"
Response
http状态码
200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误
Connection:连接方式。值有keep-alive和close
ETag:(Entity-Tag的缩写)资源的一个标识,类似于key-value pair(键值对)中的key。ETag通常用于校验一个资源实体有没有被修改过。在数据缓存和PUT方法更新资源时候有用处。例如:ETag: “737060cd8c284d8af7ad3082f209582d”
Expires:告诉客户端该响应数据会在指定的时间过期,通常用于给客户端缓存作为参考。例如:Expires: Thu, 01 Dec 1994 16:00:00 GMT
Last-Modified:客户端所请求的资源的最后修改时间。
http1.0/1.1
基于tcp协议,tcp协议建立连接需要有三次握手,断开链接时需要4次挥手
1.1 长连接(Persistent Connection)
HTTP1.1支持长连接和请求的流水线处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启长连接keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。HTTP1.0需要使用keep-alive参数来告知服务器端要建立一个长连接。
1.2 节约带宽
HTTP1.0中存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能。HTTP1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,客户端接收到100才开始把请求body发送到服务器;如果返回401,客户端就可以不用发送请求body了节约了带宽。
1.3 HOST域
在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname),HTTP1.0没有host域。随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都支持host域,且请求消息中如果没有host域会报告一个错误(400 Bad Request)。
1.4缓存处理
在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
Get post
Cookie/Session
首先一种场景, 在一个网站上面, 我发起一次请求,那服务器怎么知道我是谁?是谁发起的这次请求呢, HTTP协议是无状态的协议, 浏览器的每一次请求,服务器都当做一次新请求, 但是在实际应用中我们需要知道这个请求来自于谁,需要查找哪些信息返回给访问者,
这个时候就引入了COOKIE机制, COOKIE机制是什么呢? 其实就是服务器给客户端返回数据的时候,中间加了一个标识, 然后客户端再次请求数据的时候,数据中带上这个标识, 那么服务器接收到请求消息时就知道这个请求来自于谁了(相当于服务器接收到请求时,如果没有带识别码,生成一个识别码给客户端, 如果有识别码,就把这个识别码需要的对应内容返回给客户端)
cookie保存在客户端,比较不安全;session保存在服务器端,比较安全。
cookie目的可以跟踪会话,也可以保存用户喜好或者保存用户名密码,session用来跟踪会话。
建议用户名,密码保存在session,其它信息可保存在cookie。
1. cookie的工作机制
1、服务器向客户端响应请求的时候,会在响应头中设置set-cookie的值,其值的格式通常是name = value的格式
2、浏览器将 cookie 保存下来
3、每次请求浏览器都会自动将 cookie 发向服务器
4、cookie最初是在客户端用于存储会话信息的。
2. session的工作机制
1、当客户端第一次请求session对象时,服务器会创建一个session,并通过特殊算法算出一个session的ID,用来标识该session对象,然后将这个session序列放置到set-cookie中发送给浏览器
2、浏览器下次发请求的时候,这个sessionID会被放置在请求头中,和cookie一起发送回来
3、服务器再通过内存中保存的sessionID跟cookie中保存的sessionID进行比较,并根据ID在内存中找到之前创建的session对象,提供给请求使用,也就是服务器会通过session保存一个状态记录,浏览器会通过cookie保存状态记录,服务器通过两者的对比实现跟踪状态,这样的做,也极大的避免了cookie被篡改而带来的安全性问题
4、由于cookie可以被人为的禁止,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面
https
|
|
HTTPS是身披SSL外壳的HTTP。通过在tcp和http之间加入tls(transport layer security)来加密,HTTPS是一种通过计算机网络进行安全通信的传输协议,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。
PS:TLS是传输层加密协议,前身是SSL协议,由网景公司1995年发布,有时候两者不区分。
Tls 协议 之上的握手协议,加密协议,警告协议 加上http 协议 组成了https协议。
Https = http + 加密+ 认证 + 数据的完整性保护。
tls握手阶段是非对称加密,数据传输阶段是对称加密
加密
密钥:密钥是一种参数,它是在明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为对称密钥与非对称密钥
对称加密:加密数据用的密钥,跟解密数据用的密钥时一样的 des aes
不对称加密: 私有密钥:一方保管,公有密钥:双方共有
RSA加密过程:
1 服务端会生产一对密钥,一个私钥仅顿房在server端,仅自己知道
2 另一个是公钥要,公钥可以自由发布供任何人使用,发送给client
3 client 使用公钥加密明文传输给server
4 server使用私钥解密密文得到明文
发送密文的一方,先获得对方的共有密钥,通过加密算法进行加密,对方收到加密信息,是由自己的私有密钥进行解密。
数字证书CA:包含了很多真实服务器的公钥
是互联网通讯中标志通讯各方身份信息的一串数字。
为什么需要证书:1 对请求方来说,怎么确定自己得到的公钥是它期望的目标主机发送过来的,而没有经过第三方篡改过,需要权威机构颁发证书
数字签名:1用于验证传输的内容是不是真实的server发送的数据,2 发送的数据有没有被篡改过。是非对称加密的一种应用场景,不过他是法诺来用私钥加密,公钥解密
数字签名过程:
|
|
tls握手过程
|
|
Tcp
arp协议:可以从IP地址得到MAC地址
DNS:将主机名和域名转化成IP
okHttp
|
implementation 'com.squareup.okhttp3:okhttp:3.8.1'
implementation 'com.squareup.okio:okio:1.7.0'
OkHttpClient client = new OkHttpClient().newBuilder().readTimeout(5, TimeUnit.SECONDS).build();
public void sysRequest() {
Request request = new Request.Builder().url("http://www.baidu.com").get().build();
Call call = client.newCall(request);//Call 相当于 request 和 response 的桥梁
Response response = call.execute();// 同步方法,Call 是个借口,实际调用的是RealCall的方法
response.body();
}
public void asysRequest () {
Request request = new Request.Builder().url("http://www.baidu.com").get().build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {//都是在子线程中执行的
}
@Override
public void onResponse(Call call, Response response) throws IOException {
response.body();
}
});
}
方法小结:
1 创建OkHttpClient 和 Request对象
2 将Request封装成call对象 // client的newcall
3 调用call的execute/enqueue发送同步/异步请求。// 当前线程如果发送请求后,就会进入阻塞状态,知道收到响应。
同步请求源码分析:
public Builder newBuilder() {
return new Builder(this);
}
public static final class Builder {
Dispatcher dispatcher;
@Nullable Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
@Nullable Cache cache;
@Nullable InternalCache internalCache;
SocketFactory socketFactory;
@Nullable SSLSocketFactory sslSocketFactory;
@Nullable CertificateChainCleaner certificateChainCleaner;
HostnameVerifier hostnameVerifier;
CertificatePinner certificatePinner;
Authenticator proxyAuthenticator;
Authenticator authenticator;
ConnectionPool connectionPool;
Dns dns;
boolean followSslRedirects;
boolean followRedirects;
boolean retryOnConnectionFailure;
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
Requst build方法
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
Builder(Request request) {
this.url = request.url;
this.method = request.method;
this.body = request.body;
this.tag = request.tag;
this.headers = request.headers.newBuilder();
}
RealCall的构造方法中,构造出重定向拦截器
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
// TODO(jwilson): this is unsafe publication and not threadsafe.
this.eventListener = eventListenerFactory.create(this);
}
execute方法
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
Enqueue 方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
// 1 判断当前call 是否执行过了
// 2 封装成一个AsyncCall 对象
// 3 client。dispather。enqueue
抓包
charles/postman
// tcpflow -cp -i eth0 host 10.227.160.34 ?????
1 手机的网络需要和电脑的网络一样: 手机wifi 高级设置代理: 主机名${ifconfig} 端口:8888
2 charles proxy--proxy settings --http proxy 端口:8888
Postman new request