JavaScript权威指南笔记8_脚本化HTTP
open()
open() 的第一个参数指定HTTP的 方法/动作; 不区分大小写;但通常使用大写字幕
open() 的第二个参数是 URL; 相对于文档的URL或者绝对URL
绝对URL如果跨域,通常会报错;除非服务器允许并且XHR2规范
使用setRequestsHeader() 多次设置 POST请求通常拥有主体,同时应该使用 setRequestsHeader
指定 Content-Type
头xhr.setRequestHeader('Content-Type', 'text/plain')
无法传递以下头
_
_
_
Accept-Charset
Content-Transfer-Encoding
TE
Accept-Encoding
Date
Trailer
Connection
Expect
Transfer-Encoding
Content-Length
Host
Upgrade
Cookie
Keep-Alive
User-Agent
Cookie2
Referer
Via
open() 传递第3个参数 为 false, send()方法阻塞,以同步响应
open() 的第4个和第5个参数为用户名和密码, 请求一个受密码保护的URL
send()
GET请求没有主体, 设置为null会省略这个参数 request.send(null)
顺序:
请求方法和URL
请求头
请求主体
1 2 3 4 5 6 7 8 9 function postMessage (msg ) { var request = new XMLHttpRequest(); request.open("POST" , "/log.php" ); request.setRequestHeader("Content-Type" , "text/plain;charset=UTF-8" ); request.send(msg); }
响应
status和statusText以数字和文本的形式返回HTTP状态码
getResponseHeader() 和 getAllResponseHeaders() 能查询响应头
getAllResponseHeaders() 会过滤掉cookie头 getResponseHeader() 传递 Set-Cookie 或 Set-Cookie2 返回null
responseText 以文本形式返回响应主体
readyState
常量(IE9+)
值
含义
UNSENT
0
open() 尚未调用
OPENED
1
open() 已调用
HEADERS_RECEIVED
2
接收到头信息
LOADING
3
接收到响应主体
DONE
4
响应完成
onreadystatechange
readystatechange事件在实际中改变为0或1时可能没有触发这个事件; 当调用send()事件时,即使处于OPENED状态也触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function getText (url, callback ) { var request = new XMLHttpRequest(); request.open("GET" , url); request.onreadystatechange = function ( ) { if (request.readyState === 4 && request.status === 200 ) { var type = request.getResponseHeader("Content-Type" ); if (type.match(/^text/ )) { callback(request.responseText); } } }; request.send(null ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function getTextSync (url ) { var request = new XMLHttpRequest(); request.open("GET" , url, false ); request.send(null ); if (request.status !== 200 ) { throw new Error (request.statusText); } var type = request.getResponseHeader("Content-Type" ); if (!type.match(/^text/ )) { throw new Error ("Expected textual response; got: " + type); } return request.responseText; }
编码请求主体 表单编码请求
表单数据POST是必须设置 Content-type
表单数据编码格式MIME类型:appliaction/x-www-form-urlencoded
JSON编码请求
application/json
1 2 3 4 5 6 7 8 9 10 11 function postJSON (url, data, callback ) { var request = new XMLHttpRequest(); request.open("POST" , url); request.onreadystatechange = function ( ) { if (request.readyState === 4 && callback) callback(request); }; request.setRequestHeader("Content-Type" , "application/json" ); request.send(JSON .stringify(data)); }
自动设置
给send()传入XML文档,自动设置一个合适的头 给send()传入字符串并且没有指定 Content-Type
头, 自动添加 text/plain; charset=UTF-8
上传文件
XHR2允许向send()方法传入任何Blob对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 var whenReady = (function ( ) { var funcs = []; var ready = false ; function handler (e ) { if (ready) { return ; } if (e.type === "readystatechange" && document .readyState !== "complete" ) { return ; } for (var i = 0 ; i < funcs.length; i++) { funcs[i].call(document ); } ready = true ; funcs = null ; } if (document .addEventListener) { document .addEventListener("DOMContentLoaded" , handler, false ); document .addEventListener("readystatechange" , handler, false ); window .addEventListener("load" , handler, false ); } else if (document .attachEvent) { document .attachEvent("onreadystatechange" , handler); window .attachEvent("onload" , handler); } return function whenReady (f ) { if (ready) { f.call(document ); } else { funcs.push(f); } } }()); whenReady(function ( ) { var elts = document .getElementsByTagName("input" ); for (var i = 0 ; i < elts.length; i++) { var input = elts[i]; if (input.type !== "file" ) { continue ; } var url = input.getAttribute("data-uploadto" ); if (!url) { continue ; } input.addEventListener("change" , function ( ) { var file = this .files[0 ]; if (!file) { return ; } var xhr = new XMLHttpRequest(); xhr.open("POST" , url); xhr.send(file); }, false ); } });
当HTML表单同时包含文件上传元素和其他元素是, 使用 multipart/form-data
的 Content-Type
XHR2定义了新的 FormData API
; 使用FormData()构造函数创建FormData对象, append()方法可以多次加入File, 字符串, 或者 Blob对象, 把FormData对象传递个send()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function postFormData (url, data, callback ) { if (typeof FormData === "undefined" ) { throw new Error ("FormData is not implemented" ); } var request = new XMLHttpRequest(); request.open("POST" , url); request.onreadystatechange = function ( ) { if (request.readyState === 4 && callback) { callback(request); } }; var formdata = new FormData(); for (var name in data) { if (!data.hasOwnProperty(name)) { continue ; } var value = data[name]; if (typeof value === "function" ) { continue ; } formdata.append(name, value); } request.send(formdata); }
HTTP进度事件
完成请求触发load事件 请求超时触发timeout事件 请求中值触发abort事件 太多重定这样的网络错误出啊发error事件 对于具体的请求,浏览器只出发load/abort/timeout/error事件中的一个
onprogress事件有3个有用的属性
loaded: 目前传输的字节数 total: 自’Content-Length’头传输的数据的整体长度,不知道内容长度则为0 lengthComputable: 是否知道内容内容长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 whenReady(function ( ) { var elts = document .getElementsByClassName("fileDropTarget" ); for (var i = 0 ; i < elts.length; i++) { var target = elts[i]; var url = target.getAttribute("data-uploadto" ); if (!url) { continue ; } createFileUploadDropTarget(target, url); } function createFileUploadDropTarget (target, url ) { var uploading = false ; console .log(target, url); target.ondragenter = function (e ) { console .log("dragenter" ); if (uploading) { return ; } var types = e.dataTransfer.types; if (types && ((types.contains && types.contains("Files" )) || (types.indexOf && types.indexOf("Files" ) !== -1 ))) { target.classList.add("wantdrop" ); return false ; } }; target.ondragover = function (e ) { if (!uploading) { return false ; } }; target.ondragleave = function (e ) { if (!uploading) { target.classList.remove("wantdrop" ); } }; target.ondrop = function (e ) { if (uploading) { return false ; } var files = e.dataTransfer.files; if (files && files.length) { uploading = true ; var message = "Uploading files:<ul>" ; for (var i = 0 ; i < files.length; i++) message += "<li>" + files[i].name + "</li>" ; message += "</ul>" ; target.innerHTML = message; target.classList.remove("wantdrop" ); target.classList.add("uploading" ); var xhr = new XMLHttpRequest(); xhr.open("POST" , url); var body = new FormData(); for (var i = 0 ; i < files.length; i++) body.append(i, files[i]); xhr.upload.onprogress = function (e ) { if (e.lengthComputable) { target.innerHTML = message + Math .round(e.loaded / e.total * 100 ) + "% Complete" ; } }; xhr.upload.onload = function (e ) { uploading = false ; target.classList.remove("uploading" ); target.innerHTML = "Drop files to upload" ; }; xhr.send(body); return false ; } target.classList.remove("wantdrop" ); } } });
超时
XHR2定义了timeout属性来指定请求自动终止后的毫秒数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function timedGetText (url, timeout, callback ) { var request = new XMLHttpRequest(); var timedout = false ; var timer = setTimeout(function ( ) { timedout = true ; request.abort(); }, timeout); request.open("GET" , url); request.onreadystatechange = function ( ) { if (request.readyState !== 4 ) { return ; } if (timedout) { return ; } clearTimeout(timer); if (request.status === 200 ) { callback(request.responseText); } }; request.send(null ); }
跨域请求
XHR2通过在 HTTP响应中选择发送合适的CORS允许跨域访问网站 如果给open()方法传入 用户名和密码, 那么它们绝不会通过跨域请求发送 跨域请求通常不包括任何其它用户证书: cookie和HTTP身份令牌(token) 设置 withCredentials
属性为 true
才能发送用户证书(不常见)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 whenReady(function ( ) { var supportsCORS = (new XMLHttpRequest()).withCredentials !== undefined ; var links = document .getElementsByTagName('a' ); for (var i = 0 ; i < links.length; i++) { var link = links[i]; if (!link.href) { continue ; } if (link.title) { continue ; } if (link.host !== location.host || link.protocol !== location.protocol) { link.title = "Off-site link" ; if (!supportsCORS) { continue ; } } if (link.addEventListener) { link.addEventListener("mouseover" , mouseoverHandler, false ); } else { link.attachEvent("onmouseover" , mouseoverHandler); } } function mouseoverHandler (e ) { var link = e.target || e.srcElement; var url = link.href; var req = new XMLHttpRequest(); req.open("HEAD" , url); req.onreadystatechange = function ( ) { if (req.readyState !== 4 ) { return ; } if (req.status === 200 ) { var type = req.getResponseHeader("Content-Type" ); var size = req.getResponseHeader("Content-Length" ); var date = req.getResponseHeader("Last-Modified" ); link.title = "Type: " + type + " \n" + "Size: " + size + " \n" + "Date: " + date; } else { if (!link.title) { link.title = "Couldn't fetch details: \n" + req.status + " " + req.statusText; } } }; req.send(null ); if (link.removeEventListener) { link.removeEventListener("mouseover" , mouseoverHandler, false ); } else { link.detachEvent("onmouseover" , mouseoverHandler); } } });
文章若有纰漏请大家补充指正,谢谢~~ http://blog.xinshangshangxin.com SHANG殇