HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议(基于TCP/IP协议)。
URL与URI
HTTP URL是统一资源定位系统(uniform resource locator;URL)的简称,它包含了用于查找某个资源的完整信息,格式如下:http://host[“:”port][abs_path]
abs_path指定请求资源的URI,URI(统一资源标识符,Uniform Resource Identifier)是一个用于标识某一互联网资源名称的字符串。
HTTP请求消息(HttpRequest)
HTTP请求消息主要由三部分组成:请求行、消息头、空行、请求正文。
其中请求方法一共有九种,HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法;HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
一般最常用的HTTP请求方法是GET和POST方法。GET和POST方法的区别如下:
(1)根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的;POST则表示可能修改变服务器上的资源的请求。(幂等任意多次执行所产生的影响均与一次执行的影响相同)
(2)GET提交,请求的数据会附在URL之后,就是把数据放置在请求行(request line)中,以“?”分割URL和传输数据,多个参数用“&”连接;而POST提交会把提交的数据放置在HTTP消息的包体中,数据不会在地址栏中显示出来。
(3)传输数据的大小不同。特定浏览器和服务器对URL长度有限制,例如IE对URL长度的限制是2083字节(2K+35),因此GET携带的参数的长度会受到浏览器的限制;而POST由于不是通过URL传值,理论上数据长度不会受限。
(4)安全性。POST的安全性要比GET的安全性高。比如通过GET提交数据,用户名和密码将明文出现在URL上。因为1)登录页面有可能被浏览器缓存;2)其他人查看浏览器的历史记录,那么别人就可以拿到你的账号和密码了。除此之外,使用GET提交数据还可能会造成Cross-site request forgery(跨站请求伪造)攻击。POST提交的内容由于在消息体中传输,因此不存在上述安全问题。
HTTP响应消息(HTTPResponse)
处理完HTTP客户端的请求之后,HTTP服务端返回响应消息给客户端,HTTP响应也是由三个部分组成,分别是:状态行、消息报头、空行、响应正文。
状态行的格式为:HTTP-Version Status-Code Reason-Phrase CRLF,其中HTTP-Version表示服务器HTTP协议的版本,Status-Code表示服务器返回的响应状态代码,Status-Code表示服务器返回的响应状态代码。
状态码由三位数字组成,第一位数字定义了响应的类别,总共有5种。
(1)1xx:指示信息。表示请求已接收,继续处理;
(2)2xx:成功。表示请求已被成功接收、理解、接受;
(3)3xx:重定向。要完成请求必须进行更进一步的操作;
(4)4xx:客户端错误。请求有语法错误或请求无法实现;
(5)5xx:服务器端错误。服务器未能处理请求。
常见的HTTP状态码和描述信息如下:
Netty构建HTTP文件服务器
HttpFileServer类:
package com.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
public class HttpFileServer {
private static final String DEFAULT_URL = "/src/com/";
public void run(final int port, final String url) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());
ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());
ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
ch.pipeline().addLast("fileServerHandler", new HttpFileServerHandler(url));
}
});
ChannelFuture future = b.bind("127.0.0.1", port).sync