# HTTP协议入门——1.1版本
### 基本概述
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。在Internet上的Web服务器上存放的都是超文本信息,客户机需要通过HTTP协议传输所要访问的超文本信息。HTTP包含命令和传输信息,不仅可用于Web访问,也可以用于其他因特网/内联网应用系统之间的通信,从而实现各类应用资源超媒体访问的集成。
### 长连接和短连接的区别
解释1
所谓长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差,
所谓短连接指建立SOCKET连接后发送后接收完数据后马上断开连接,一般银行都使用短连接
解释2
长连接就是指在基于tcp的通讯中,一直保持连接,不管当前是否发送或者接收数据。
而短连接就是只有在有数据传输的时候才进行连接,客户-服务器通信/传输数据完毕就关闭连接。
解释3
长连接和短连接这个概念好像只有移动的CMPP协议中提到了,其他的地方没有看到过。
通信方式
各网元之间共有两种连接方式:长连接和短连接。所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接。短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,即每次TCP连接只完成一对 CMPP消息的发送。
现阶段,要求ISMG之间必须采用长连接的通信方式,建议SP与ISMG之间采用长连接的通信方式。
解释4
短连接:比如http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。
长连接:有些服务需要长时间连接到服务器,比如CMPP,一般需要自己做在线维持。
参考文章:[http://blog.csdn.net/shine0181/article/details/7799754](http://blog.csdn.net/shine0181/article/details/7799754)
### HTTP请求部分
#### 基本结构
GET /q547550831?viewmode=contents HTTP/1.1 [请求行]
Host: blog.csdn.net [消息头] 消息名:内容
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Referer: http://blog.csdn.net/q547550831?viewmode=contents
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
PS:这是我博客主页的请求头,但是这并不代表每个网页的请求头都是这一样的。
#### 请求方式
请求方式有:
POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT,CONNECT等
参考文档:[http://tools.jb51.net/table/http_request_method](http://tools.jb51.net/table/http_request_method)
常用的有:POST和GET
#### 请求消息头
Host: blog.csdn.net [主机名]
Connection: keep-alive [连接状态:保持连接]
Cache-Control: max-age=0 [指定请求和响应遵循的缓存机制:查看是否有修改并选择更新否]
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 [可接受的格式]
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 [浏览器内核]
Referer: [http://blog.csdn.net/q547550831?viewmode=contents](http://blog.csdn.net/q547550831?viewmode=contents) [从哪个网页跳转到这个网页来的,可以用来防盗链]
Accept-Encoding: gzip, deflate, sdch [可接收的压缩格式]
Accept-Language: zh-CN,zh;q=0.8 [浏览器支持的语言]
PS:请求是指浏览器发出向服务器发出,所以这些信息都是浏览器的信息。请求头远远不止这几种,可以参考该文档:[http://tools.jb51.net/table/http_header](http://tools.jb51.net/table/http_header)
案例:防止盗链
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.println("<a href='http://127.0.0.1:8080/servlet1/Servlet5'>连接到Servlet5</a>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 通过request对象来获取http请求信息
// 取出Host
String host = request.getHeader("Host");
out.println("host=" + host);
// 限制用户
// 获取用户浏览器的Referer
// referer可以防止盗链,通过判断链接来至哪里
String referer = request.getHeader("Referer");
if(referer == null || !referer.startsWith("http://127.0.0.1:8080/servlet1")){
out.println("非法盗链");
} else {
out.println("referer=" + referer);
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 一般开发人员习惯把doGet()和doPost()合二为一
this.doGet(request, response);
}
public void init() throws ServletException {
// Put your code here
}
}
~~~
PS:该案例中只能允许http://127.0.0.1:8080/servlet1开头的网址进行访问Servlet5
### HTTP响应部分
#### 基本结构
HTTP/1.1 200 OK [状态行]
Server: openresty [消息名] 消息名:内容
Date: Fri, 01 Jan 2016 08:11:04 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: private
Set-Cookie: uuid=5cad65d6-7a99-4b15-a6e6-5c50e584ca77; expires=Sat, 02-Jan-2016 08:13:49 GMT; path=/
Set-Cookie: ViewMode=contents; path=/
Content-Encoding: gzip
**--------------这是一个空行**
**消息体**
#### 响应状态码
响应状态码分别为1,2,3,4,5开头的三位数字
<table><tbody><tr><td valign="center"><p style="text-align:left">1** </p></td><td valign="center"><p style="text-align:left">信息,服务器收到请求,需要请求者继续执行操作</p></td></tr><tr><td valign="center"><p style="text-align:left">2** </p></td><td valign="center"><p style="text-align:left">成功,操作被成功接收并处理</p></td></tr><tr><td valign="center"><p style="text-align:left">3** </p></td><td valign="center"><p style="text-align:left">重定向,需要进一步的操作以完成请求</p></td></tr><tr><td valign="center"><p style="text-align:left">4** </p></td><td valign="center"><p style="text-align:left">客户端错误,请求包含语法错误或无法完成请求</p></td></tr><tr><td valign="center"><p style="text-align:left">5** </p></td><td valign="center"><p style="text-align:left">服务器错误,服务器在处理请求的过程中发生了错误</p></td></tr></tbody></table>
PS:常见的有200(成功),303(重定向),400(Not Found),500(服务器内部错误)
可以参考该文档:[http://tools.jb51.net/table/http_status_code](http://tools.jb51.net/table/http_status_code)
#### 响应消息头
Server: openresty [服务器名称]
Date: Fri, 01 Jan 2016 08:11:04 GMT [原始服务器消息发出的时间]
Content-Type: text/html; charset=utf-8 [返回内容的MIME类型]
Transfer-Encoding: chunked [文件传输编码]
Connection: keep-alive [连接状态:保持连接]
Vary: Accept-Encoding [告诉下游代理是使用缓存响应还是从原始服务器请求]
Cache-Control: private [告诉所有的缓存机制是否可以缓存及哪种类型]
Set-Cookie: uuid=********; expires=Sat, 02-Jan-2016 08:13:49 GMT; path=/ [设置Http Cookie]
Set-Cookie: ViewMode=contents; path=/ [设置Http Cookie]
Content-Encoding: gzip [web服务器支持的返回内容压缩编码类型]
PS:可以参考该文档[http://tools.jb51.net/table/http_header](http://tools.jb51.net/table/http_header)
### 缓存机制
浏览器默认情况下,会缓存所访问的页面,这样会出现一个问题:如果用户习惯把光标停留在地址栏,然后回车来取页面,就会默认调用cache中取数据。
案例1、有些网站要求及时性很高,因此要求不缓存页面。
//指定该页面不缓存 Ie
response.setDateHeader("Expires", -1);【针对IE浏览器设置不缓存】
//为了保证兼容性.
response.setHeader("Cache-Control", "no-cache");【针对火狐浏览器等】
response.setHeader("Pragma", "no-cache");【其他浏览器】
案例2、有些网站要求网页缓存一定时间,比如缓存一个小时
response.setDateHeader("Expires", System.currentTimeMillis()+3600*1000); //后面一个参数表示设置的缓存保持时间,-1表示永远不缓存
### Content-Type消息头
Content-Type,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件
PS:其作用就是告诉浏览器,该服务器返回的网页中消息体是什么格式的,该以什么编码格式来读取这个网页。
因为该类型很多,故给出参考文档,以备后用:[http://tools.jb51.net/table/http_content_type](http://tools.jb51.net/table/http_content_type)
案例1:定时刷新Refresh的使用
response.setHeader("Refresh", "5;url=/servletPro/Servlet2"); // 5秒后刷新并跳转到url后的链接。通过这个可以实现页面定时刷新。
案例2:文件下载
~~~
package com.pc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
// 演示下载文件
response.setHeader("Content-Disposition", "attachment; filename=EVO_120G.jpg");
// 打开文件
// 1.获取到要下载文件的全路径
String path = this.getServletContext().getRealPath("/EVO_120G.jpg");
// 测试
System.out.println("path=" + path);
// 2.创建文件输入流
FileInputStream fis = new FileInputStream(new File(path));
// 做一个缓冲字符数组
byte buff[] = new byte[1024];
int length = 0;
// 3.指向response的输出流
OutputStream os = response.getOutputStream();
// 4.循环读出
// length表示每次实际读入的字节数
while((length = fis.read(buff)) != -1){
os.write(buff, 0, length);
}
// 关闭
os.close();
fis.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
----------参考《韩顺平.细说Servlet》