文章目录
一、URL 简介
概述
URL 是“统一资源定位符”(Uniform Resource Locator)的首字母缩写,中文译为“网址”,表示各种资源的互联网地址。下面就是URL的语法规则。
scheme://host.domain:port/path/filename?parameter#anchor
说明:
-
- scheme - 定义因特网服务的类型(协议),最常见的类型是 http,https(协议后面紧跟://,注意:其他协议不一定,如邮件地址协议的协议名后面只有一个冒号,如:
mailto:foo@example.com) - host - 定义域主机(http 的默认主机是 www)
- domain - 定义因特网域名,比如 baidu.com
- :port - 定义主机上的端口号(http 的默认端口号是 80)
- path - 定义服务器上的路径(如果省略,则文档必须位于网站的根目录中)
- filename - 定义文档/资源的名称
- parameter - 定义查询参数(参数的位置在路径后面使用?分隔,可以有一组或是多组,每组参数都是键值对的形式,如:key1=value1;多组参数之间使用&连接,如:key1=value1&key2=value2)
- anchor - 定义锚点(网页内部的定位点,使用#加上锚点名称,锚点名称通过网页元素的id属性命名)
- scheme - 定义因特网服务的类型(协议),最常见的类型是 http,https(协议后面紧跟://,注意:其他协议不一定,如邮件地址协议的协议名后面只有一个冒号,如:
URL 字符
URL 的各个组成部分,只能使用以下这些字符。
-
26个英语字母(包括大写和小写)
-
10个阿拉伯数字
-
连词号(
-) -
句点(
.) -
下划线(
_)
此外,还有18个字符属于 URL 的保留字符,只能在给定的位置出现。比如,查询参数的开头是问号(?),也就是说,问号只能出现查询参数的开头,出现在其他位置就是非法的,会导致网址解析错误。网址的其他部分如果要使用这些保留字符,必须使用它们的转义形式。
URL 字符转义的方法是,在这些字符的十六进制 ASCII 码前面加上百分号(%)。URL 不能包含空格。URL 编码通常使用 + 来替换空格。下面是这18个字符及其转义形式。
!:%21#:%23$:%24&:%26':%27(:%28):%29*:%2A+:%2B,:%2C/:%2F::%3A;:%3B=:%3D?:%3F@:%40[:%5B]:%5D
举例来说,有一个网页的 URL 是foo?bar.html,即文件里面包含一个问号,那么需要写成foo%3Fbar.html。
URL 的合法字符,其实也可以采用这种转义方法,但是不建议使用。比如,字母a的十六进制 ASCII 码是61,转义形式后就是%61。因此,www.apple.com又可以写成www.%61pple.com,浏览器一样识别。
值得注意的是,空格的转义形式是%20。对于那些包含空格的文件名,这个转义是必须的。
既不属于合法字符、也不属于保留字符的其他字符(比如汉字),理论上不需要手动转义,可以直接写在 URL 里面,比如www.example.com/中国.html,浏览器会自动将它们转义,发给服务器。转义方法是使用这些字符的十六进制 UTF-8 编码,每两位算作一组,然后每组头部添加百分号(%)。
举例来说,汉字中的 UTF-8 十六进制编码是e4b8ad,每两个字符一组,URL 转义后就为%e4%b8%ad。也就是说,URL 里面凡是有汉字中的地方,都要写成%e4%b8%ad。因此,访问www.example.com/中国.html这个网址,需要写成下面的样子。
www.example.com/%e4%b8%ad%e5%9b%bd.html
URL 编码参考手册
| ASCII 字符 | URL-编码 | ASCII 字符 | URL-编码 |
|---|---|---|---|
| space | %20 | P | %50 |
| ! | %21 | Q | %51 |
| " | %22 | R | %52 |
| # | %23 | S | %53 |
| $ | %24 | T | %54 |
| % | %25 | U | %55 |
| & | %26 | V | %56 |
| ’ | %27 | W | %57 |
| ( | %28 | X | %58 |
| ) | %29 | Y | %59 |
| * | %2A | Z | %5A |
| + | %2B | [ | %5B |
| , | %2C | \ | %5C |
| - | %2D | ] | %5D |
| . | %2E | ^ | %5E |
| / | %2F | _ | %5F |
| 0 | %30 | ` | %60 |
| 1 | %31 | a | %61 |
| 2 | %32 | b | %62 |
| 3 | %33 | c | %63 |
| 4 | %34 | d | %64 |
| 5 | %35 | e | %65 |
| 6 | %36 | f | %66 |
| 7 | %37 | g | %67 |
| 8 | %38 | h | %68 |
| 9 | %39 | i | %69 |
| : | %3A | j | %6A |
| ; | %3B | k | %6B |
| < | %3C | l | %6C |
| = | %3D | m | %6D |
| > | %3E | n | %6E |
| ? | %3F | o | %6F |
| @ | %40 | p | %70 |
| A | %41 | q | %71 |
| B | %42 | r | %72 |
| C | %43 | s | %73 |
| D | %44 | t | %74 |
| E | %45 | u | %75 |
| F | %46 | v | %76 |
| G | %47 | w | %77 |
| H | %48 | x | %78 |
| I | %49 | y | %79 |
| J | %4A | z | %7A |
| K | %4B | { | %7B |
| L | %4C | | | %7C |
| M | %4D | } | %7D |
| N | %4E | ~ | %7E |
| O | %4F | %7F |
绝对 URL 和相对 URL
URL 分成两种:绝对 URL 和相对 URL。
绝对 URL 指的是,只靠 URL 本身就能确定资源的位置。这意味着,URL 必须带有资源的完整信息,包含协议、主机、路径等部分。前面的例子都是绝对 URL。
相对 URL 指的是,URL 不包含资源位置的全部信息,必须结合当前网页的位置,才能定位资源。比如,当前网页的 URL 是https://www.example.com/path/index.html,该网页上面有一个资源,URL 指向a.html,这个就是相对 URL。因为只知道a.html,并不能定位资源。浏览器假定,a.html与当前网址在同一个子目录下面,从而得到绝对 URL https://www.example.com/path/a.html。
相对 URL 如果以斜杠(/)开头,就表示网站的根目录。否则,必须以当前目录为起点,推算资源的位置。比如,相对 URL /foo/bar.html表示网站根目录的子目录foo,foo/bar.html表示在当前目录的foo子目录。
URL 还可以使用两个特殊简写,表示特定位置。
.:表示当前目录,比如./a.html(当前目录下的a.html文件)..:表示上级目录,比如../a.html(上级目录下的a.html文件)
这两种简写可以多个连用,比如../../表示上两级目录。
绝对 URL 也可以使用这两个简写,比如www.example.com/./index.html等同于www.example.com/index.html,这时.相当于根目录的当前目录,即根目录本身。
二、ASCII 码和非ASCII 编码
ASCII码
我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从00000000到11111111。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。
ASCII 码一共规定了128个字符的编码,比如空格SPACE是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的一位统一规定为0。
ASCII 可打印的字符
| 字符 | 编号 | 描述 | 字符 | 编号 | 描述 |
|---|---|---|---|---|---|
| 32 | 空格(space) | Q | 81 | 大写字母 Q | |
| ! | 33 | 感叹号(exclamation mark) | R | 82 | 大写字母 R |
| " | 34 | 引号(quotation mark) | S | 83 | 大写字母 S |
| # | 35 | 数字符号(number sign) | T | 84 | 大写字母 T |
| $ | 36 | 美元符号(dollar sign) | U | 85 | 大写字母 U |
| % | 37 | 百分比符号(percent sign) | V | 86 | 大写字母 V |
| & | 38 | & 符号(ampersand) | W | 87 | 大写字母 W |
| ’ | 39 | 撇号(apostrophe) | X | 88 | 大写字母 X |
| ( | 40 | 左括号(left parenthesis) | Y | 89 | 大写字母 Y |
| ) | 41 | 右括号(right parenthesis) | Z | 90 | 大写字母 Z |
| * | 42 | 星号(asterisk) | [ | 91 | 左方括号(left square bracket) |
| + | 43 | 加号(plus sign) | \ | 92 | 反斜线(backslash) |
| , | 44 | 逗号(comma) | ] | 93 | 右方括号(right square bracket) |
| - | 45 | 连字符(hyphen) | ^ | 94 | 插入符号(caret) |
| . | 46 | 句号(period) | _ | 95 | 下划线(underscore) |
| / | 47 | 斜线(slash) | ` | 96 | 重音符(grave accent) |
| 0 | 48 | 数字 0 | a | 97 | 小写字母 a |
| 1 | 49 | 数字 1 | b | 98 | 小写字母 b |
| 2 | 50 | 数字 2 | c | 99 | 小写字母 c |
| 3 | 51 | 数字 3 | d | 100 | 小写字母 d |
| 4 | 52 | 数字 4 | e | 101 | 小写字母 e |
| 5 | 53 | 数字 5 | f | 102 | 小写字母 f |
| 6 | 54 | 数字 6 | g | 103 | 小写字母 g |
| 7 | 55 | 数字 7 | h | 104 | 小写字母 h |
| 8 | 56 | 数字 8 | i | 105 | 小写字母 i |
| 9 | 57 | 数字 9 | j | 106 | 小写字母 j |
| : | 58 | 冒号(colon) | k | 107 | 小写字母 k |
| ; | 59 | 分号(semicolon) | l | 108 | 小写字母 l |
| < | 60 | 小于号(less-than) | m | 109 | 小写字母 m |
| = | 61 | 等于号(equals-to) | n | 110 | 小写字母 n |
| > | 62 | 大于号(greater-than) | o | 111 | 小写字母 o |
| ? | 63 | 问号(question mark) | p | 112 | 小写字母 p |
| @ | 64 | @ 符号(at sign) | q | 113 | 小写字母 q |
| A | 65 | 大写字母 A | r | 114 | 小写字母 r |
| B | 66 | 大写字母 B | s | 115 | 小写字母 s |
| C | 67 | 大写字母 C | t | 116 | 小写字母 t |
| D | 68 | 大写字母 D | u | 117 | 小写字母 u |
| E | 69 | 大写字母 E | v | 118 | 小写字母 v |
| F | 70 | 大写字母 F | w | 119 | 小写字母 w |
| G | 71 | 大写字母 G | x | 120 | 小写字母 x |
| H | 72 | 大写字母 H | y | 121 | 小写字母 y |
| I | 73 | 大写字母 I | z | 122 | 小写字母 z |
| J | 74 | 大写字母 J | { | 123 | 左花括号(left curly brace) |
| K | 75 | 大写字母 K | | | 124 | 竖线(vertical bar) |
| L | 76 | 大写字母 L | } | 125 | 右花括号(right curly brace) |
| M | 77 | 大写字母 M | ~ | 126 | 波浪线(tilde) |
| N | 78 | 大写字母 N | |||
| O | 79 | 大写字母 O | |||
| P | 80 | 大写字母 P |
ASCII 设备控制字符
ASCII 控制字符(00-31,加上 127)最初被设计用来控制诸如打印机和磁带驱动器之类的硬件设备。
控制字符(除了水平制表符、换行、回车之外)在 HTML 文档中不起任何作用。
| 字符 | 编号 | 描述 |
|---|---|---|
| NUL | 00 | 空字符(null character) |
| SOH | 01 | 标题开始(start of header) |
| STX | 02 | 正文开始(start of text) |
| ETX | 03 | 正文结束(end of text) |
| EOT | 04 | 传输结束(end of transmission) |
| ENQ | 05 | 请求(enquiry) |
| ACK | 06 | 收到通知/响应(acknowledge) |
| BEL | 07 | 响铃(bell) |
| BS | 08 | 退格(backspace) |
| HT | 09 | 水平制表符(horizontal tab) |
| LF | 10 | 换行(line feed) |
| VT | 11 | 垂直制表符(vertical tab) |
| FF | 12 | 换页(form feed) |
| CR | 13 | 回车(carriage return) |
| SO | 14 | 不用切换(shift out) |
| SI | 15 | 启用切换(shift in) |
| DLE | 16 | 数据链路转义(data link escape) |
| DC1 | 17 | 设备控制 1(device control 1) |
| DC2 | 18 | 设备控制 2(device control 2) |
| DC3 | 19 | 设备控制 3(device control 3) |
| DC4 | 20 | 设备控制 4(device control 4) |
| NAK | 21 | 拒绝接收/无响应(negative acknowledge) |
| SYN | 22 | 同步空闲(synchronize) |
| ETB | 23 | 传输块结束(end transmission block) |
| CAN | 24 | 取消(cancel) |
| EM | 25 | 已到介质末端/介质存储已满(end of medium) |
| SUB | 26 | 替补/替换(substitute) |
| ESC | 27 | 溢出/逃离/取消(escape) |
| FS | 28 | 文件分隔符(file separator) |
| GS | 29 | 组分隔符(group separator) |
| RS | 30 | 记录分隔符(record separator) |
| US | 31 | 单元分隔符(unit separator) |
| DEL | 127 | 删除(delete) |
非 ASCII 编码
英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用 ASCII 码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。
但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0–127表示的符号是一样的,不一样的只是128–255的这一段。
至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是 GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示 256 x 256 = 65536 个符号。
三、Unicode
世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字都表示的,这是一种所有符号的编码。
Unicode 当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字严。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。
**注意:**Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
比如,汉字严的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。
这里就有两个严重的问题,第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
它们造成的结果是:1)出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。2)Unicode 在很长一段时间内无法推广,直到互联网的出现。
四、UTF-8
互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表总结了编码规则,字母x表示可用编码的位。
Unicode符号范围 | UTF-8编码方式 (十六进制) | (二进制) ----------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 范围:0-127 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 范围:128-2047 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 范围:2048-65535 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 范围:65536-1114111
跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
下面,还是以汉字严为例,演示如何实现 UTF-8 编码。
严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。
五、HTML 字符编码/HTML实体编码
简介
网页包含了大量的文字,浏览器必须知道这些文字的编码方法,才能把文字还原出来。
一般情况下,服务器向浏览器发送 HTML 网页文件时,会通过 HTTP 头信息,声明网页的编码方式。
Content-Type: text/html; charset=UTF-8
上面代码中,HTTP 头信息的Content-Type字段先声明,服务器发送的数据类型是text/html(即 HTML 网页),然后声明网页的文字编码是UTF-8。
网页内部也会再用<meta>标签,再次声明网页的编码。
<meta charset="UTF-8">
字符的数字表示法
网页可以使用不同语言的编码方式,但是最常用的编码是 UTF-8。UTF-8 编码是 Unicode 字符集的一种表达方式。这个字符集的设计目标是包含世界上的所有字符,目前已经收入了十多万个字符。
每个字符有一个 Unicode 号码,称为码点(code point)。如果知道码点,就能查到这是什么字符。举例来说,英文字母a的码点是十进制的97(十六进制的61),汉字“中”的码点是十进制的20013(十六进制的4e2d)。
由于下面的原因,不是每一个 Unicode 字符都能直接在 HTML 语言里面显示。
(1)不是每个 Unicode 字符都可以打印出来,有些没有可打印形式,比如换行符的码点是十进制的10(十六进制的A),就没有对应的字面形式。
(2)小于号(<)和大于号(>)用来定义 HTML 标签,其他需要用到这两个符号的场合,必须防止它们被解释成标签。
(3)由于 Unicode 字符太多,无法找到一种输入法,可以直接输入所有这些字符。换言之,没有一种键盘,有办法输入所有符号。
(4)网页不允许混合使用多种编码,如果使用 UTF-8 编码的同时,又想插入其他编码的字符,就会很困难。
HTML 为了解决上面这些问题,允许使用 Unicode 码点表示字符,浏览器会自动将码点转成对应的字符。
字符的码点表示法是&#N;(十进制,N代表码点)或者&#xN;(十六进制,N代表码点),比如,字符a可以写成a(十进制)或者a(十六进制),字符中可以写成中(十进制)或者中(十六进制),浏览器会自动转换它们。
<p>hello</p>
<!-- 等同于 -->
十进制
<p>hello</p>
<!-- 等同于 -->
十六进制
<p>hello</p>
上面代码中,字符可以直接表示,也可以使用十进制码点或十六进制码点表示。
注意,HTML 标签本身不能使用码点表示,否则浏览器会认为这是所要显示的文本内容,而不是标签。比如,<p>一旦写成<p>或者<p>,浏览器就不再认为这是标签了,而会当作文本内容将其显示为<p>。
字符的实体表示法
数字表示法的不方便之处,在于必须知道每个字符的码点,很难记忆。为了能够快速输入,HTML 为一些特殊字符,规定了容易记忆的名字,允许通过名字来表示它们,这称为实体表示法(entity)。
实体的写法是&name;,其中的name是字符的名字。下面是其中一些特殊字符,及其对应的实体。
<:<>:>":"':'&:&©:©#:#§:§¥:¥$:$£:£¢:¢%:%*:$ast;@:@^:^±:±- 空格:
注意,上面最后一个特殊字符是空格,它也有对应的实体表示法。
字符的数字表示法和实体表示法,都可以表示正常情况无法输入的字符,逃脱了浏览器的限制,所以英语里面称为“escape”,中文翻译为“字符的转义”。
六、HTTP 状态码
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含 HTTP 状态码的信息头(server header)用以响应浏览器的请求。
HTTP 状态码的英文为 HTTP Status Code。
下面是常见的 HTTP 状态码:
- 200 - 请求成功
- 301 - 资源(网页等)被永久转移到其它URL
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
HTTP 状态码分类
HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599):
| 分类 | 分类描述 |
|---|---|
| 1** | 信息,服务器收到请求,需要请求者继续执行操作 |
| 2** | 成功,操作被成功接收并处理 |
| 3** | 重定向,需要进一步的操作以完成请求 |
| 4** | 客户端错误,请求包含语法错误或无法完成请求 |
| 5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
HTTP状态码列表
| 状态码 | 状态码英文名称 | 中文描述 |
|---|---|---|
| 100 | Continue | 继续。客户端应继续其请求 |
| 101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
| 200 | OK | 请求成功。一般用于GET与POST请求 |
| 201 | Created | 已创建。成功请求并创建了新的资源 |
| 202 | Accepted | 已接受。已经接受请求,但未处理完成 |
| 203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
| 204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
| 205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
| 206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
| 300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
| 301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
| 302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
| 303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
| 304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
| 305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
| 306 | Unused | 已经被废弃的HTTP状态码 |
| 307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
| 400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
| 401 | Unauthorized | 请求要求用户的身份认证 |
| 402 | Payment Required | 保留,将来使用 |
| 403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
| 404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
| 405 | Method Not Allowed | 客户端请求中的方法被禁止 |
| 406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
| 407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
| 408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
| 409 | Conflict | 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突 |
| 410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
| 411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
| 412 | Precondition Failed | 客户端请求信息的先决条件错误 |
| 413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
| 414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
| 415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
| 416 | Requested range not satisfiable | 客户端请求的范围无效 |
| 417 | Expectation Failed | 服务器无法满足Expect的请求头信息 |
| 500 | Internal Server Error | 服务器内部错误,无法完成请求 |
| 501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
| 502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 |
| 503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
| 504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
| 505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
浅析http状态码301、302、303、307、308区别
http的重定向我们经常是张口就来,整个流程也非常简单,服务端HTTP返回码是30x,头里面的Location字段代表新的URL。如下图所示:

但重定向也还是有需要深入探讨地方,返回码不仅有我们经常使用301和303还有302 307 308 它们有啥区别呢。可以按照是否缓存和重定向方法,两个维度去拆分。
| 缓存(永久重定向) | 不缓存(临时重定向) | |
|---|---|---|
| 转GET | 301 | 302、303 |
| 方法保持 | 308 | 307 |
如果是永久重定向那么浏览器客户端就会缓存此次重定向结果,下次如果有请求则直接从缓存读取,譬如我们切换域名,将所有老域名的流量转入新域名,可以使用永久重定向。
如果只是临时重定向那么浏览器则不会缓存,譬如我们的服务临时升级,会使用临时重定向。
方法保持的意思是原请求和重定向的请求是否使用相同的方法,譬如原请求是POST提交一个表单,如果是301重定向的话,重定向的请求会转为GET重新提交,如果是308则会保持原来POST请求不变。
RFC协议规范
- 301 Moved Permanently,永久重定向
- 302 Found
- 303 See Other
- 307 Temporary Redirect
- 308 Permanent Redirect 永久重定向
基本结论
- 3XX开头的HTTP状态码都表示重定向的响应。
- 301、308是永久重定向;302、303、307是临时重定向。
- 301、302是http 1.0的内容,303、307、308是http1.1的内容。
- 301和302本来在http/1.0规范中是不允许重定向时改变请求method的(将POST改为GET),实际许多浏览器实现的时候允许重定向时改变请求method。这就出现了规范和实现不一致的问题
- 302,303,307的出现,都是基于HTTP/1.1兼容HTTP/1.0规范和实现的差异性;
- 303的出现是允许重定向时改变请求method
- 307、308则不允许重定向时改变请求method
- 此外303响应禁止被缓存。
HTTP/1.0
301
301状态码在HTTP 1.0和HTTP 1.1规范中均代表永久重定向,对于资源请求,原来的url和响应头中location的url而言,资源应该对应location中的url。对于post请求的重定向,还是需要用户确认之后才能重定向,并且应该以post方法发出重定向请求。
关于post请求重定向用户确认的问题,实际上浏览器都没有实现;而且post请求的重定向应该发起post请求,这里浏览器也并不一定遵守,所以说HTTP规范的实现并未严格按照HTTP规范的语义。
在301中资源对应的路径修改为location的url,在SEO中并未出现问题,但是在302中就出现了302劫持问题
302
在http 1.0规范中,302表示临时重定向,location中的地址不应该被认为是资源路径,在后续的请求中应该继续使用原地址。
- 规范
- 原请求是post,则不能自动进行重定向;原请求是get,可以自动重定向;
- 实现
- 浏览器和服务器的实现并没有严格遵守HTTP中302的规范,服务器不加遵守的返回302,浏览器即便原请求是post也会自动重定向,导致规范和实现出现了二义性,由此衍生了一些问题,譬如302劫持,因此在HTTP 1.1中将302的规范细化成了303和307,希望以此来消除二义性。
- 302劫持
- A站通过重定向到B站的资源xxoo,A站实际上什么都没做但是有一个比较友好的域名,web资源xxoo存在B站并由B站提供,但是B站的域名不那么友好,因此对搜索引擎而言,可能会保存A站的地址对应xxoo资源而不是B站,这就意味着B站出了资源版权、带宽、服务器的钱,但是用户通过搜索引擎搜索xxoo资源的时候出来的是A站,A站什么都没做却被搜索引擎广而告之用户,B站做了一切却不被用户知道,价值被A站窃取了。
HTTP/1.1
301
和http 1.0规范中保持一致,注意资源对应的路径应该是location中返回的url,而不再是原请求地址。
302
在HTTP 1.1中,实际上302是不再推荐使用的,只是为了兼容而作保留。规范中再次重申只有当原请求是GET or HEAD方式的时候才能自动的重定向,为了消除HTTP 1.0中302的二义性,在HTTP 1.1中引入了303和307来细化HTTP 1.0中302的语义。
303
在HTTP 1.0的时候,302的规范是原请求是post不可以自动重定向,但是服务器和浏览器的实现是运行重定向。
把HTTP 1.0规范中302的规范和实现拆分开,分别赋予HTTP 1.1中303和307,因此在HTTP 1.1中,303继承了HTTP 1.0中302的实现(即原请求是post,也允许自动进行重定向,结果是无论原请求是get还是post,都可以自动进行重定向),而307则继承了HTTP 1.0中302的规范(即如果原请求是post,则不允许进行自动重定向,结果是post不重定向,get可以自动重定向)
307
在http 1.1规范中,307为临时重定向,注意划红线的部分,如果重定向307的原请求不是get或者head方法,那么浏览器一定不能自动的进行重定向,即便location有url,也应该忽略。
也就是307继承了302在HTTP 1.0中的规范(303继承了302在HTTP 1.0中的实现)。
308
308与301定义一致,唯一的区别在于,308状态码不允许浏览器将原本为POST的请求重定向到GET请求上。
302
在php的header("location:")中,如果没有明确写明状态码的话,会默认是302跳转,也就是常说的临时跳转,在seo领域里面,302并不转移权重值。
303
HTTP 303 See Other 重定向状态码,通常作为 PUT 或 POST 操作的返回结果,它表示重定向链接指向的不是新上传的资源,而是另外一个页面,比如消息确认页面或上传进度页面。而请求重定向页面的方法要总是使用 GET。
304
304状态码,304状态码的解释时:Not Modified。这个状态码并不涉及任何的页面跳转,只是告诉浏览器,资源没有修改,使用缓存就好了,并且并不会返回任何响应主体,所以,304并不跳。
307
307跳转中,因为会转移_POST值,可以用于表单第三方表单验证,大家可以仔细体会体会。
浏览器对307状态的处理规则和302状态相同。之所以将值307引入到HTTP/1.1中,是因为,甚至在最初的消息是POST的情况下,许多浏览器依旧错误地跟随302响应中的重定向信息,浏览器应该只在接收到303状态码时才跟从POST请求的重定向信息。引入这个新状态是为了消除二义性:如果接收到303响应,则继续进行GET和POST请求的重定向;如果接收到307响应,对于GET请求的重定向,则继续进行;但对于POST请求的重定向,则不再继续下去。这是HTTP/1.1新引入的状态码。
342

被折叠的 条评论
为什么被折叠?



