[JavaScript基础]学习③⑤--AJAX

参考地址

http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html

http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499861493e7c35be5e0864769a2c06afb4754acc6000

Asynchronous JavaScript and XML (用JavaScript执行异步网络请求)

Web的运作原理:一次HTTP请求对应一个页面。

如果要让用户留在当前页面中,同时发出新的HTTP请求,就必须用JavaScript发送这个新请求,接收到数据后,再用JavaScript更新页面,这样一来,用户就感觉自己仍然停留在当前页面,但是数据却可以不断地更新。

AJAX请求是异步执行的

AJAX主要依靠XMLHttpRequest对象

<textarea id="test-response-text" rows="5" style="width: 90%; margin: 15px 0; resize: none;">
响应结果:
</textarea>
'use strict';
function success(text) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = text;
}

function fail(code) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = 'Error code: ' + code;
}

var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象

request.onreadystatechange = function () { // 状态发生变化时,函数被回调
    if (request.readyState === 4) { // 成功完成
        // 判断响应结果:
        if (request.status === 200) {
            // 成功,通过responseText拿到响应的文本:
            return success(request.responseText);
        } else {
            // 失败,根据响应码判断失败原因:
            return fail(request.status);
        }
    } else {
        // HTTP请求还在继续...
    }
}

// 发送请求:
request.open('GET', 'https://myrailsshop.herokuapp.com/products.json');
request.send();

alert('请求已发送,请等待响应...');

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript">


        function onC() {
            'use strict';
            function success(text) {
                var textarea = document.getElementById('test-response-text');
                textarea.value = text;
            }

            function fail(code) {
                var textarea = document.getElementById('test-response-text');
                textarea.value = 'Error code: ' + code;
            }

            var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象

            request.onreadystatechange = function () { // 状态发生变化时,函数被回调
                if (request.readyState === 4) { // 成功完成
                    // 判断响应结果:
                    if (request.status === 200) {
                        // 成功,通过responseText拿到响应的文本:
                        return success(request.responseText);
                    } else {
                        // 失败,根据响应码判断失败原因:
                        return fail(request.status);
                    }
                } else {
                    // HTTP请求还在继续...
                }
            }

            request.open('GET', 'https://myrailsshop.herokuapp.com/products.json');
            request.send();

            alert('请求已发送,请等待响应...');
        }
    </script>
</head>
<body>
<textarea id="test-response-text" rows="5" style="width: 90%; margin: 15px 0; resize: none;">
响应结果:
</textarea>

<input type="button" onclick="onC()" value="Get"/>

</body>
</html>

对于低版本的IE,需要换一个ActiveXObject对象

'use strict';
function success(text) {
    var textarea = document.getElementById('test-ie-response-text');
    textarea.value = text;
}

function fail(code) {
    var textarea = document.getElementById('test-ie-response-text');
    textarea.value = 'Error code: ' + code;
}

var request = new ActiveXObject('Microsoft.XMLHTTP'); // 新建Microsoft.XMLHTTP对象

request.onreadystatechange = function () { // 状态发生变化时,函数被回调
    if (request.readyState === 4) { // 成功完成
        // 判断响应结果:
        if (request.status === 200) {
            // 成功,通过responseText拿到响应的文本:
            return success(request.responseText);
        } else {
            // 失败,根据响应码判断失败原因:
            return fail(request.status);
        }
    } else {
        // HTTP请求还在继续...
    }
}

// 发送请求:
request.open('GET', '/api/categories');
request.send();

alert('请求已发送,请等待响应...');

标准写法和IE写法混在一起

var request;
if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();
} else {
    request = new ActiveXObject('Microsoft.XMLHTTP');
}

readyState === 4判断请求是否完成
status === 200判断是否是一个成功的响应

open()方法

第一个参数 GET还是POST
第二个参数 URL地址
第三个参数 是否使用异步,默认是true

send()方法发送请求

默认情况下,JavaScript在发送AJAX请求时,######URL的域名必须和当前页面完全一致。
域名相同(www.example.comexample.com不同)
协议相同(http和https不同)
端口号要相同(默认是:80端口,它和:8080就不同)

JavaScript请求外域的URL

①Flash插件发送HTTP请求
②同源域名下架设一个代理服务器
③JSONP 只能用GET请求,要求返回JavaScript

<html>
<head>
    <script src="http://example.com/abc.js"></script>
    ...
</head>
<body>
...
</body>
</html>
foo('data');

163举例 跨域加载数据

http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice

返回

refreshPrice({"0000001":{"code": "0000001", ... });

回调

function refreshPrice(data) {
    var p = document.getElementById('test-jsonp');
    p.innerHTML = '当前价格:' +
        data['0000001'].name +': ' + 
        data['0000001'].price + ';' +
        data['1399001'].name + ': ' +
        data['1399001'].price;
}

函数触发

function getPrice() {
    var
        js = document.createElement('script'),
        head = document.getElementsByTagName('head')[0];
    js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice';
    head.appendChild(js);
}

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript">

        function refreshPrice(data) {
            var p = document.getElementById('test-jsonp');
            p.innerHTML = '当前价格:' +
                data['0000001'].name + ': ' +
                data['0000001'].price + ';' +
                data['1399001'].name + ': ' +
                data['1399001'].price;
        }
        function getPrice() {
            var
                js = document.createElement('script'),
                head = document.getElementsByTagName('head')[0];
            js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice';
            head.appendChild(js);
        }
    </script>
</head>
<body>
<p id="test-jsonp">当前价格:</p>
<button type="button" onclick="getPrice()">刷新</button>


</body>
</html>

CORS(HTML5)

跨域策略 全称Cross-Origin Resource Sharing
Origin:本域

当JavaScript向外域(如sina.com)发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。

Paste_Image.png

假设本域是my.com,外域是sina.com,只要响应头Access-Control-Allow-Origin为http://my.com,或者是*,本次请求就可以成功。

可见,跨域能否成功,取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin,决定权始终在对方手中。

上面这种跨域请求,称之为“简单请求”。简单请求包括GET、HEAD和POST(POST的Content-Type类型
仅限application/x-www-form-urlencoded、multipart/form-data和text/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足90%的需求。

无论你是否需要用JavaScript通过CORS跨域请求资源,你都要了解CORS的原理。最新的浏览器全面支持HTML5。在引用外域资源时,除了JavaScript和CSS外,都要验证CORS。例如,当你引用了某个第三方CDN上的字体文件时:

/* CSS */
@font-face {
  font-family: 'FontAwesome';
  src: url('http://cdn.com/fonts/fontawesome.ttf') format('truetype');
}

如果该CDN服务商未正确设置Access-Control-Allow-Origin,那么浏览器无法加载字体资源。

对于PUT、DELETE以及其他类型如application/json的POST请求,在发送AJAX请求之前,浏览器会先发送一个OPTIONS请求(称为preflighted请求)到这个URL上,询问目标服务器是否接受:

OPTIONS /path/to/resource HTTP/1.1
Host: bar.com
Origin: http://my.com
Access-Control-Request-Method: POST

服务器必须响应并明确指出允许的Method:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://my.com
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 86400

浏览器确认服务器响应的Access-Control-Allow-Methods
头确实包含将要发送的AJAX请求的Method,才会继续发送AJAX,否则,抛出一个错误。
由于以POST、PUT方式传送JSON格式的数据在REST中很常见,所以要跨域正确处理POST和PUT请求,服务器端必须正确响应OPTIONS请求。
需要深入了解CORS的童鞋请移步W3C文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容

  • Ajax:Asynchronous JavaScript + XML的简写。Ajax技术的核心是XMLHttpRe...
    exialym阅读 866评论 0 8
  • 跑步,但是脑子里还满是各种念头、想法。现在的我慢慢感受到,我遇到的能够让我喜欢上的人,都是来告诉我,如果正确的...
    ohon阅读 405评论 0 1
  • 什么事情值得去做,与成长并联的事情。 对同一概念反复打磨,对同一事情反复思考。都会体现在写作中。在写作的过程中,也...
    Liu小喵_cb95阅读 98评论 0 0
  • Android系统启动流程 当系统引导程序启动Linux内核,内核会记载各种数据结构,和驱动程序,加载完毕之后,A...
    插兜阅读 451评论 1 5
  • 我们分开很久了,久到我已经有了新的爱好,久到我甚至都不知道你近况如何,每每別人问起,我都会说自己恨你讨厌你说你种种...
    荒芜杂陈阅读 412评论 1 1