urllib模块
什么是urllib模块:
urllib是python提供的一个用操作url的模块,在Python2.X中,有urllib库,也有urllib2,在python3.X中urllib2合并到了urllib中。包括以下模块:
urllib.request 请求模块
urllib.error 异常处理模块
urllib.parse url解析模块
urllib.robotparser robots.txt解析模块
urlopen
关于urllib.request.urlopen参数的介绍:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
url参数的使用(三种打开网页方法):
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request url = "http://www.baidu.com" response = urllib.request.urlopen(url) # 打开网页 html = response.read() # 读取全部内容 # html = response.readlines() # 读取全部内容,返回一个列表 # html = response.readline() # 返回一行内容 print(html.decode("utf-8"))
timeout参数的使用(网页超时):
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request for i in range(1, 10): try: url = "http://www.baidu.com" response = urllib.request.urlopen(url, timeout=0.1) html = response.read() print(len(html)) except Exception as e: print("出现异常-->" + str(e)) 结果: 出现异常-->timed out 出现异常-->timed out 出现异常-->timed out 出现异常-->timed out 出现异常-->timed out 118729 出现异常-->timed out 118488 118536
data参数:
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request import urllib.parse url = "http://httpbin.org/post" data = bytes(urllib.parse.urlencode({"word": "hello"}), encoding="utf-8") respones = urllib.request.urlopen(url, data=data) print(respones.read()) # 这里就用到urllib.parse,通过bytes(urllib.parse.urlencode())可以将post数据进行转换放到urllib.request.urlopen的data参数中。这样就完成了一次post请求。所以如果我们添加data参数的时候就是以post请求方式请求,如果没有data参数就是get请求方式.
对异常进行抓取:
import urllib.request import socket import urllib.error try: url = "http://www.baidu.com/get" response = urllib.request.urlopen(url, timeout=0.1) except urllib.error.URLError as e: if isinstance(e.reason, socket.timeout): print("TIME OUT")
响应类型、状态码、响应头:
#!/urs/bin/env python # -*- coding:utf-8 -*- import urllib.request url = "http://www.baidu.com" response = urllib.request.urlopen(url) print(type(response)) # 类型 print(response.status) # 状态码 print(response.getcode()) # 状态码 print(response.info()) # 服务器响应的HTML报头 print(response.getheaders()) #服务器响应的HTML报头
print(response.getheader("Server")) # 服务器 print(response.geturl()) # 获取当前url print(urllib.request.quote(url)) # 对当前url编码 print(urllib.request.unquote(url)) # 对当前url解码
响应头 (704 字节) Bdpagetype 1 Bdqid 0xe2a789bb000253dc Cache-Control private Connection Keep-Alive Content-Encoding gzip Content-Type text/html Cxy_all monline_3_dg+e3e5470c4eb212ac85d2f2ede7280e85 Date Thu, 25 Oct 2018 15:37:19 GMT Expires Thu, 25 Oct 2018 15:37:19 GMT P3p CP=" OTI DSP COR IVA OUR IND COM " Server BWS/1.1 Set-Cookie BDRCVFR[Fc9oatPmwxn]=G01CoNusk…P8; path=/; domain=.baidu.com Set-Cookie delPer=0; path=/; domain=.baidu.com Set-Cookie BDSVRTM=8; path=/ Set-Cookie BD_HOME=0; path=/ Set-Cookie H_PS_PSSID=1459_21126_27401_27342; path=/; domain=.baidu.com Strict-Transport-Security max-age=172800 Transfer-Encoding chunked Vary Accept-Encoding X-Ua-Compatible IE=Edge,chrome=1 请求头 (710 字节) Accept text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8 Accept-Encoding gzip, deflate, br Accept-Language zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Cache-Control max-age=0 Connection keep-alive Cookie BAIDUID=999FB83DA2F96790A7F927…_PSSID=1459_21126_27401_27342 Host www.baidu.com Referer https://home.firefoxchina.cn/ Upgrade-Insecure-Requests 1 User-Agent Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/62.0
urlopen只能用于一些简单的请求,因为它无法添加一些header信息,就用到了urllib.request。
request:
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request """ 设置Headers 有很多网站为了防止程序爬虫爬网站造成网站瘫痪,会需要携带一些headers头部信息才能访问 """ url = "https://www.cnblogs.com/zqxqx/p/9308912.html" requests = urllib.request.Request(url) response = urllib.request.urlopen(requests) print(response.read().decode("utf-8"))
1.add_header添加请求头:
#!/urs/bin/evn python # -*- coding:utf-8 -*- from urllib import request, parse url = "http://httpbin.org/post" dict = { "name": "Germey" } data = bytes(parse.urlencode(dict), encoding="utf-8") req = request.Request(url=url, data=data, method="POST") req.add_header("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36") response = request.urlopen(req) print(response.read().decode("utf-8"))
2.给请求添加头部信息,从而定制自己请求网站是时的头部信息:
#!/urs/bin/evn python # -*- coding:utf-8 -*- from urllib import request, parse url = "http://httpbin.org/post" headers = { "User-Agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36", "Host":"httpbin.org" } dicts ={ "name":"Germey" } data = bytes(parse.urlencode(dicts), encoding="utf-8") req = request.Request(url=url, data=data, headers=headers, method="POST") respones = request.urlopen(req) print(respones.read().decode("utf-8"))
3.修改报头:
#!/urs/bin/env python # -*- coding:utf-8 -*- from urllib import request url = "http://httpbin.org" headers = { "User-Agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36", "Host":"httpbin.org" } req = request.build_opener() req.addheaders = [headers] response = req.open(url).read() print(response.decode("utf-8"))
文件写入:
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request url = "http://www.baidu.com" respones = urllib.request.urlretrieve(url, "cc.html") # 文件路径 urllib.request.urlcleanup() # 清除缓存 print(respones)
代理:
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request import urllib.error def use_proxy(proxy_addr, url): """ 代理服务器来爬某个URL网页功能 :param proxy_addr: 代理服务器地址 :param url: 网页地址 :return: """ proxy = urllib.request.ProxyHandler({"http": proxy_addr}) opener = urllib.request.build_opener(proxy, urllib.request.HTTPHandler) urllib.request.install_opener(opener) data = urllib.request.urlopen(url).read().decode("utf-8") return data if __name__ == '__main__': proxy_addr = "163.125.71.254:8888" url = "http://www.baidu.com" try: response = use_proxy(proxy_addr, url) print(len(response)) except urllib.error.URLError as e: print("响应时间久,连接失败") """ urllib.request.ProxyHandler来设置对应代理服务器信息,格式:urllib.request.ProxyHandler({"http": proxy_addr}) urllib.request.build_opener创建一个自定义的opener对象,第一个参数是代理信息,第二个参数urllib.request.HTTPHandler类 urllib.request.install_opener()创建全局默认的opener对象,在使用URLopen()时亦会使用我们安装的opener对象,所以下面才可以直接使用urllib.request.urlopen()打开对应网址爬取网页读取 """
user-agent大全:
Opera Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60 Opera/8.0 (Windows NT 5.1; U; en) Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50 Firefox Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10 Safari Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2 chrome Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11 Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16 360 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko 淘宝浏览器 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11 猎豹浏览器 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER) Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)" QQ浏览器 Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400) Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E) sogou浏览器 Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0) maxthon浏览器 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36 UC浏览器 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36 ==================== 移动浏览器大全 ==================== IPhone Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5 IPod Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5 IPAD Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5 Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5 Android Mozilla/5.0 (Linux; U; Android 2.2.1; zh-cn; HTC_Wildfire_A3333 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 QQ浏览器 Android版本 MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 Android Opera Mobile Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10 Android Pad Moto Xoom Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13 BlackBerry Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+ WebOS HP Touchpad Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0 Nokia N97 Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124 Windows Phone Mango Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan) UC浏览器 UCWEB7.0.2.37/28/999 NOKIA5700/ UCWEB7.0.2.37/28/999 UCOpenwave Openwave/ UCWEB7.0.2.37/28/999 UC Opera Mozilla/4.0 (compatible; MSIE 6.0; ) Opera/UCWEB7.0.2.37/28/999
cookie:
什么是cookie:
访问一个互联网页面,都是通过HTTP协议进行的,而HTTP协议是一个无状态协议,即无法维持会话之间的状态。
将对应的会话信息,通过一些方法保存下来。方式有两种:
通过Cookie保存会话信息或通过Session保存会话信息。
如果是通过Cookie保存会话信息,此时会将所有的会话信息保存在客户端,当我们访问同一个网站的其他页面的时候,会从Cookie中读取对应的会话信息,从而判断目前的会话状态,比如可以判断是否已经登录。
通过Session保存会话信息,会将对应的会话信息保存在服务器端,但是服务器端会给客户端发SessionID等信息,这些信息一般存在客户端的Cookie中,当然,如果客户端禁止了Cookie,也会通过其他方式存储。用户在访问该网站其他网页的时候,会从cookie中读取这一部分信息,然后,用户从服务器中的Session中根据这一部分Cookie信息检索出该客户端的所有会话信息,然后进行会话控制,使用Session的方式保存会话信息。
cookie可以写入到文件中保存,有两种方式http.cookiejar.MozillaCookieJar和http.cookiejar.LWPCookieJar()。
1.http.cookiejar.MozillaCookieJar
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request, http.cookiejar url = "http://www.baidu.com" filename = "cookie.txt" cookie = http.cookiejar.MozillaCookieJar(filename) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open(url) cookie.save(ignore_discard=True, ignore_expires=True) # 将cookie写入文本
2.http.cookiejar.LWPCookieJar()方式
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request, http.cookiejar url = "http://www.baidu.com" filename = "cookie1.txt" cookie = http.cookiejar.LWPCookieJar(filename) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open(url) cookie.save(ignore_discard=True, ignore_expires=True)
如果想要通过获取文件中的cookie获取的话可以通过load方式,当然用哪种方式写入的,就用哪种方式读取
#!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request, http.cookiejar url = "http://www.baidu.com" # cookie = http.cookiejar.LWPCookieJar() cookie = http.cookiejar.MozillaCookieJar() # 如果想要通过获取文件中的cookie获取的话可以通过load方式,当然用哪种方式写入的,就用哪种方式读取 cookie.load("cookie.txt", ignore_discard=True, ignore_expires=True,) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open(url) print(response.read().decode("utf-8"))
无cookie登录:
异常处理:
产生URLError的原因有:
连接不上服务器
远程url不存在
无网络
触发了HTTPError
#!/urs/bin/evn python # -*- coding:utf-8 -*- from urllib import request, error try: url = "http://cc.com/index.html" response = request.urlopen(url) except error.URLError as e: print(e.reason)
URLError,HTTPError,HTTPError是URLError的子类。
URLError里只有一个属性:reason,即抓异常的时候只能打印错误信息。
HTTPError里有三个属性:code,reason,headers,即抓异常的时候可以获得code,reson,headers三个信息
!/urs/bin/evn python # -*- coding:utf-8 -*- import urllib.request, errno url = "http://www.baiduvvv.com" try: urllib.request.urlopen(url) except urllib.request.HTTPError as e: print(e.code) print(e.reason) print(e.headers) except urllib.request.URLError as e: print(e.reason)
URL解析:
urlparse:对传入的url地址进行拆分
urllib.parse.urlparse(urlsting, scheme="", allow_fragments=True)
# -*- coding:utf-8 -*- from urllib.parse import urlparse url = "http://www.baidu.com/index.html;user?id=5#comment" result = urlparse(url) print(result) print(type(result)) 结果: ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment') <class 'urllib.parse.ParseResult'>
urlunpars,urljoin:用于拼接。
from urllib.parse import urljoin print(urljoin('http://www.baidu.com', 'FAQ.html')) print(urljoin('http://www.baidu.com', 'https://pythonsite.com/FAQ.html')) print(urljoin('http://www.baidu.com/about.html', 'https://pythonsite.com/FAQ.html')) print(urljoin('http://www.baidu.com/about.html', 'https://pythonsite.com/FAQ.html?question=2')) print(urljoin('http://www.baidu.com?wd=abc', 'https://pythonsite.com/index.php')) print(urljoin('http://www.baidu.com', '?category=2#comment')) print(urljoin('www.baidu.com', '?category=2#comment')) print(urljoin('www.baidu.com#comment', '?category=2'))
from urllib.parse import urlunparse data = ['http','www.baidu.com','index.html','user','a=123','commit'] print(urlunparse(data))
urlencode:
这个方法可以将字典转换为url参数
from urllib.parse import urlencode params = { "name":"cc", "age":24, } base_url = "http://www.baidu.com?" url = base_url+urlencode(params) print(url)
状态码:
HTTP状态码大全 完整的 HTTP 1.1规范说明书来自于RFC 2616,你可以在http://www.talentdigger.cn/home/link.php?url=d3d3LnJmYy1lZGl0b3Iub3JnLw%3D%3D在线查阅。HTTP 1.1的状态码被标记为新特性,因为许多浏览器只支持 HTTP 1.0。你应只把状态码发送给支持 HTTP 1.1的客户端,支持协议版本可以通过调用request.getRequestProtocol来检查。 本部分余下的内容会详细地介绍 HTTP 1.1中的状态码。这些状态码被分为五大类: 100-199 用于指定客户端应相应的某些动作。 200-299 用于表示请求成功。 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。 400-499 用于指出客户端的错误。 500-599 用于支持服务器错误。 HttpServletResponse中的常量代表关联不同标准消息的状态码。在servlet程序中,你会更多地用到这些常量的标识来使用状态码。例如:你一般会使用response.setStatus(response.SC_NO_CONTENT)而不是 response.setStatus(204),因为后者不易理解而且容易导致错误。但是,你应当注意到服务器允许对消息轻微的改变,而客户端只注意状态码的数字值。所以服务器可能只返回 HTTP/1.1 200 而不是 HTTP/1.1 200 OK。 100 (Continue/继续) 如果服务器收到头信息中带有100-continue的请求,这是指客户端询问是否可以在后续的请求中发送附件。在这种情况下,服务器用100(SC_CONTINUE)允许客户端继续或用417 (Expectation Failed)告诉客户端不同意接受附件。这个状态码是 HTTP 1.1中新加入的。 101 (Switching Protocols/转换协议) 101 (SC_SWITCHING_PROTOCOLS)状态码是指服务器将按照其上的头信息变为一个不同的协议。这是 HTTP 1.1中新加入的。 200 (OK/正常) 200 (SC_OK)的意思是一切正常。一般用于相应GET和POST请求。这个状态码对servlet是缺省的;如果没有调用setStatus方法的话,就会得到200。 201 (Created/已创建) 201 (SC_CREATED)表示服务器在请求的响应中建立了新文档;应在定位头信息中给出它的URL。 202 (Accepted/接受) 202 (SC_ACCEPTED)告诉客户端请求正在被执行,但还没有处理完。 203 (Non-Authoritative Information/非官方信息) 状态码203 (SC_NON_AUTHORITATIVE_INFORMATION)是表示文档被正常的返回,但是由于正在使用的是文档副本所以某些响应头信息可能不正确。这是 HTTP 1.1中新加入的。 204 (No Content/无内容) 在并没有新文档的情况下,204 (SC_NO_CONTENT)确保浏览器继续显示先前的文档。这各状态码对于用户周期性的重载某一页非常有用,并且你可以确定先前的页面是否已经更新。例如,某个servlet可能作如下操作: int pageVersion =Integer.parseInt(request.getParameter("pageVersion")); if (pageVersion >;= currentVersion) { response.setStatus(response.SC_NO_CONTENT); } else { // Create regular page } 但是,这种方法对通过刷新响应头信息或等价的HTML标记自动重载的页面起作用,因为它会返回一个204状态码停止以后的重载。但基于JavaScript脚本的自动重载在这种情况下仍然需要能够起作用。可以阅读本书7.2 ( HTTP 1.1 Response Headers and Their Meaning/HTTP 1.1响应头信息以及他们的意义)部分的详细讨论。 205 (Reset Content/重置内容) 重置内容205 (SC_RESET_CONTENT)的意思是虽然没有新文档但浏览器要重置文档显示。这个状态码用于强迫浏览器清除表单域。这是 HTTP 1.1中新加入的。 206 (Partial Content/局部内容) 206 (SC_PARTIAL_CONTENT)是在服务器完成了一个包含Range头信息的局部请求时被发送的。这是 HTTP 1.1中新加入的。 300 (Multiple Choices/多重选择) 300 (SC_MULTIPLE_CHOICES)表示被请求的文档可以在多个地方找到,并将在返回的文档中列出来。如果服务器有首选设置,首选项将会被列于定位响应头信息中。 301 (Moved Permanently) 301 (SC_MOVED_PERMANENTLY)状态是指所请求的文档在别的地方;文档新的URL会在定位响应头信息中给出。浏览器会自动连接到新的URL。 302 (Found/找到) 与301有些类似,只是定位头信息中所给的URL应被理解为临时交换地址而不是永久的。注意:在 HTTP 1.0中,消息是临时移动(Moved Temporarily)的而不是被找到,因此HttpServletResponse中的常量是SC_MOVED_TEMPORARILY不是我们以为的SC_FOUND。 注意 代表状态码302的常量是SC_MOVED_TEMPORARILY而不是SC_FOUND。 状态码302是非常有用的因为浏览器自动连接在定为响应头信息中给出的新URL。这非常有用,而且为此有一个专门的方法——sendRedirect。使用response.sendRedirect(url)比调用response.setStatus(response.SC_MOVED_TEMPORARILY)和response.setHeader("Location", url)多几个好处。首先,response.sendRedirect(url)方法明显要简单和容易。第二,servlet自动建立一页保存这一连接以提供给那些不能自动转向的浏览器显示。最后,在servlet 2.2版本(J2EE中的版本)中,sendRedirect能够处理相对路径,自动转换为绝对路径。但是你只能在2.1版本中使用绝对路径。 如果你将用户转向到站点的另一页中,你要用 HttpServletResponse 中的 encodeURL 方法传送URL。这么做可预防不断使用基于URL重写的会话跟踪的情况。URL重写是一种在你的网站跟踪不使用 cookies 的用户的方法。这是通过在每一个URL尾部附加路径信息实现的,但是 servlet 会话跟踪API会自动的注意这些细节。会话跟踪在第九章讨论,并且养成使用 encodeURL 的习惯会使以后添加会话跟踪的功能更容易很多。 核心技巧 如果你将用户转向到你的站点的其他页面,用 response.sendRedirect(response.encodeURL(url)) 的方式事先计划好会话跟踪(session tracking)要比只是调用 response.sendRedirect(url) 好的多。 这个状态码有时可以与301交换使用。例如,如果你错误的访问了http://www.talentdigger.cn/home/link.php?url=aG9zdC9%2BdXNlcg%3D%3D(路径信息不完整),有些服务器就会回复301状态码而有些则回复302。从技术上说,如果最初的请求是GET浏览器只是被假定自动转向。如果想了解更多细节,请看状态码307的讨论。 303 (See Other/参见其他信息) 这个状态码和 301、302 相似,只是如果最初的请求是 POST,那么新文档(在定位头信息中给出)药用 GET 找回。这个状态码是新加入 HTTP 1.1中的。 304 (Not Modified/为修正) 当客户端有一个缓存的文档,通过提供一个 If-Modified-Since 头信息可指出客户端只希望文档在指定日期之后有所修改时才会重载此文档,用这种方式可以进行有条件的请求。304 (SC_NOT_MODIFIED)是指缓冲的版本已经被更新并且客户端应刷新文档。另外,服务器将返回请求的文档及状态码 200。servlet一般情况下不会直接设置这个状态码。它们会实现getLastModified方法并根据修正日期让默认服务方法处理有条件的请求。这个方法的例程已在2.8部分(An Example Using Servlet Initialization and Page Modification Dates/一个使用servlet初始化和页面修正日期的例子)给出。 305 (Use Proxy/使用代理) 305 (SC_USE_PROXY)表示所请求的文档要通过定位头信息中的代理服务器获得。这个状态码是新加入 HTTP 1.1中的。 307 (Temporary Redirect/临时重定向) 浏览器处理307状态的规则与302相同。307状态被加入到 HTTP 1.1中是由于许多浏览器在收到302响应时即使是原始消息为POST的情况下仍然执行了错误的转向。只有在收到303响应时才假定浏览器会在POST请求时重定向。添加这个新的状态码的目的很明确:在响应为303时按照GET和POST请求转向;而在307响应时则按照GET请求转向而不是POST请求。注意:由于某些原因在HttpServletResponse中还没有与这个状态对应的常量。该状态码是新加入HTTP 1.1中的。 注意 在 HttpServletResponse 中没有 SC_TEMPORARY_REDIRECT 常量,所以你只能显示的使用307状态码。 400 (Bad Request/错误请求) 400 (SC_BAD_REQUEST)指出客户端请求中的语法错误。 401 (Unauthorized/未授权) 401 (SC_UNAUTHORIZED)表示客户端在授权头信息中没有有效的身份信息时访问受到密码保护的页面。这个响应必须包含一个WWW-Authenticate的授权信息头。例如,在本书4.5部分中的“Restricting Access to Web Pages./限制访问Web页。” 403 (Forbidden/禁止) 403 (SC_FORBIDDEN)的意思是除非拥有授权否则服务器拒绝提供所请求的资源。这个状态经常会由于服务器上的损坏文件或目录许可而引起。 404 (Not Found/未找到) 404 (SC_NOT_FOUND)状态每个网络程序员可能都遇到过,他告诉客户端所给的地址无法找到任何资源。它是表示“没有所访问页面”的标准方式。这个状态码是常用的响应并且在HttpServletResponse类中有专门的方法实现它:sendError("message")。相对于setStatus使用sendError得好处是:服务器会自动生成一个错误页来显示错误信息。但是,Internet Explorer 5浏览器却默认忽略你发挥的错误页面并显示其自定义的错误提示页面,虽然微软这么做违反了 HTTP 规范。要关闭此功能,在工具菜单里,选择Internet选项,进入高级标签页,并确认“显示友好的 HTTP 错误信息”选项(在我的浏览器中是倒数第8各选项)没有被选。但是很少有用户知道此选项,因此这个特性被IE5隐藏了起来使用户无法看到你所返回给用户的信息。而其他主流浏览器及IE4都完全的显示服务器生成的错误提示页面。可以参考图6-3及6-4中的例子。 核心警告 默认情况下,IE5忽略服务端生成的错误提示页面。 405 (Method Not Allowed/方法未允许) 405 (SC_METHOD_NOT_ALLOWED)指出请求方法(GET, POST, HEAD, PUT, DELETE, 等)对某些特定的资源不允许使用。该状态码是新加入 HTTP 1.1中的。 406 (Not Acceptable/无法访问) 406 (SC_NOT_ACCEPTABLE)表示请求资源的MIME类型与客户端中Accept头信息中指定的类型不一致。见本书7.2部分中的表7.1(HTTP 1.1 Response Headers and Their Meaning/HTTP 1.1响应头信息以及他们的意义)中对MIME类型的介绍。406是新加入 HTTP 1.1中的。 407 (Proxy Authentication Required/代理服务器认证要求) 407 (SC_PROXY_AUTHENTICATION_REQUIRED)与401状态有些相似,只是这个状态用于代理服务器。该状态指出客户端必须通过代理服务器的认证。代理服务器返回一个Proxy-Authenticate响应头信息给客户端,这会引起客户端使用带有Proxy-Authorization请求的头信息重新连接。该状态码是新加入 HTTP 1.1中的。 408 (Request Timeout/请求超时) 408 (SC_REQUEST_TIMEOUT)是指服务端等待客户端发送请求的时间过长。该状态码是新加入 HTTP 1.1中的。 409 (Conflict/冲突) 该状态通常与PUT请求一同使用,409 (SC_CONFLICT)状态常被用于试图上传版本不正确的文件时。该状态码是新加入 HTTP 1.1中的。 410 (Gone/已经不存在) 410 (SC_GONE)告诉客户端所请求的文档已经不存在并且没有更新的地址。410状态不同于404,410是在指导文档已被移走的情况下使用,而404则用于未知原因的无法访问。该状态码是新加入 HTTP 1.1中的。 411 (Length Required/需要数据长度) 411 (SC_LENGTH_REQUIRED)表示服务器不能处理请求(假设为带有附件的POST请求),除非客户端发送Content-Length头信息指出发送给服务器的数据的大小。该状态是新加入 HTTP 1.1的。 412 (Precondition Failed/先决条件错误) 412 (SC_PRECONDITION_FAILED)状态指出请求头信息中的某些先决条件是错误的。该状态是新加入 HTTP 1.1的。 413 (Request Entity Too Large/请求实体过大) 413 (SC_REQUEST_ENTITY_TOO_LARGE)告诉客户端现在所请求的文档比服务器现在想要处理的要大。如果服务器认为能够过一段时间处理,则会包含一个Retry-After的响应头信息。该状态是新加入 HTTP 1.1的。 414 (Request URI Too Long/请求URI过长) 414 (SC_REQUEST_URI_TOO_LONG)状态用于在URI过长的情况时。这里所指的“URI”是指URL中主机、域名及端口号之后的内容。例如:在URL--http://www.y2k-disaster.com:8080/we/look/silly/now/中URI是指/we/look/silly/now/。该状态是新加入 HTTP 1.1的。 415 (Unsupported Media Type/不支持的媒体格式) 415 (SC_UNSUPPORTED_MEDIA_TYPE)意味着请求所带的附件的格式类型服务器不知道如何处理。该状态是新加入 HTTP 1.1的。 416 (Requested Range Not Satisfiable/请求范围无法满足) 416表示客户端包含了一个服务器无法满足的Range头信息的请求。该状态是新加入 HTTP 1.1的。奇怪的是,在servlet 2.1版本API的HttpServletResponse中并没有相应的常量代表该状态。 注意 在servlet 2.1的规范中,类HttpServletResponse并没有SC_REQUESTED_RANGE_NOT_SATISFIABLE 这样的常量,所以你只能直接使用416。在servlet 2.2版本之后都包含了此常量。 417 (Expectation Failed/期望失败) 如果服务器得到一个带有100-continue值的Expect请求头信息,这是指客户端正在询问是否可以在后面的请求中发送附件。在这种情况下,服务器也会用该状态(417)告诉浏览器服务器不接收该附件或用100 (SC_CONTINUE)状态告诉客户端可以继续发送附件。该状态是新加入 HTTP 1.1的。 500 (Internal Server Error/内部服务器错误) 500 (SC_INTERNAL_SERVER_ERROR) 是常用的“服务器错误”状态。该状态经常由CGI程序引起也可能(但愿不会如此!)由无法正常运行的或返回头信息格式不正确的servlet引起。 501 (Not Implemented/未实现) 501 (SC_NOT_IMPLEMENTED)状态告诉客户端服务器不支持请求中要求的功能。例如,客户端执行了如PUT这样的服务器并不支持的命令。 502 (Bad Gateway/错误的网关) 502 (SC_BAD_GATEWAY)被用于充当代理或网关的服务器;该状态指出接收服务器接收到远端服务器的错误响应。 503 (Service Unavailable/服务无法获得) 状态码503 (SC_SERVICE_UNAVAILABLE)表示服务器由于在维护或已经超载而无法响应。例如,如果某些线程或数据库连接池已经没有空闲则servlet会返回这个头信息。服务器可提供一个Retry-After头信息告诉客户端什么时候可以在试一次。 504 (Gateway Timeout/网关超时) 该状态也用于充当代理或网关的服务器;它指出接收服务器没有从远端服务器得到及时的响应。该状态是新加入 HTTP 1.1的。 505 (HTTP Version Not Supported/不支持的 HTTP 版本) 505 (SC_HTTP_VERSION_NOT_SUPPORTED)状态码是说服务器并不支持在请求中所标明 HTTP 版本。该状态是新加入 HTTP 1.1的。