1-Web - Ajax

about

摘自:https://developer.mozilla.org/zh-CN/docs/Glossary/AJAX
Ajax的概念由杰西·詹姆士·贾瑞特所提出,AJAX(Asynchronous JavaScript And XML,异步的JavaScript与XML技术 )是一种使用 XMLHttpRequest 技术构建更复杂,动态的网页的编程实践。
AJAX允许只更新一个 HTML 页面的部分 DOM,而无须重新加载整个页面。AJAX还允许异步工作,这意味着当网页的一部分正试图重新加载时,您的代码可以继续运行(相比之下,同步会阻止代码继续运行,直到这部分的网页完成重新加载)。
通过交互式网站和现代 Web 标准,AJAX正在逐渐被 JavaScript 框架中的函数和官方的 Fetch API 标准取代。

Ajax与XMLHttpRequest
Ajax是一种技术方案,但并不是一种新技术。它依赖的是现有的CSS/HTML/Javascript,而其中最核心的依赖是浏览器提供的XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。
可以总结为:我们使用XMLHttpRequest对象来发送一个Ajax请求。

XMLHttpRequest

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
摘自:阮一峰: XMLHttpRequest Level 2 使用指南

什么是 XMLHttpRequest 对象?
XMLHttpRequest 对象用于在后台与服务器交换数据,最早,微软在IE 5引进了这个接口。因为它太有用,其他浏览器也模仿部署了,ajax操作因此得以诞生。但是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不同(此时可以将XMLHttpRequest划分为 level 1版本)。HTML 5的概念形成后,W3C开始考虑标准化这个接口。2008年2月,就提出了XMLHttpRequest Level 2 草案。
XMLHttpRequest它的优点:

  • 在不重新加载页面的情况下更新网页
  • 在页面已加载后从服务器请求数据
  • 在页面已加载后从服务器接收数据
  • 在后台向服务器发送数据

XMLHttpRequest level 1 有以下缺点:

  • 受同源策略的限制,不能发送跨域请求。
  • 不能发送二进制文件(如图片、视频、音频等),只能发送纯文本数据。
  • 在发送和获取数据的过程中,无法实时获取进度信息,只能判断是否完成。

XMLHttpRequest level 2 中做了相应的优化和扩展:

  • 可以发送跨域请求,在服务端允许的情况下。
  • 支持发送和接收二进制数据。
  • 新增formData对象,支持发送表单数据。
  • 发送和获取数据时,可以获取进度信息。
  • 可以设置请求的超时时间。

来个level 2 版本的GET请求示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XMLHttpRequest</title>
</head>
<body>
</body>
<script>
    // XMLHttpRequest使用有4个步骤
    // 1. 实例化XMLHttpRequest对象, 注意,区分大小写
    var xhr = new XMLHttpRequest();  // xhr: ajax对象

    // 2. 构建http请求
    /* xhr.open(methods, url)
        methods: 字符串类型的值,请求类型
        url: 字符串类型的值,请求的url
    */
    xhr.open('get', 'http://wthrcdn.etouch.cn/weather_mini?city=郑州')

    // 3. 发送请求
    xhr.send()

    // 4. 获取服务端响应数据
    xhr.onreadystatechange = function () { 
        /* xhr.readyState表示xhr的状态码: 
            1 表示ajx对象刚创建
            2 表示ajax请求构建完成
            3 表示ajax请求已发送到服务端
            4 表示客户端已经获取到服务端返回的数据结果,很明显这个用的多
        */ 
        if(xhr.readyState == 4){
            // 一般服务器响应成功返回200
            if(xhr.status == 200){
                data = JSON.parse(xhr.responseText);
                console.log(data);
            }else{
                console.log(xhr.status);
            }
            
        }
    }
</script>
</html>

再来个POST请求示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XMLHttpRequest</title>
</head>
<body>
</body>
<script>
    var xhr = new XMLHttpRequest();
    xhr.open('post', 'http://www.httpbin.org/post')  // 这个接口有点慢
    // post请求如果携带请求数据,就按照下面的示例写
    xhr.send("name=zhangkai&age=18")
    xhr.onreadystatechange = function () {
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                console.log(xhr.responseText);
            }
        }
      }
</script>
</html>

上面这两个示例,可以说是使用基于JavaScript实现的原生Ajax了。但我们已经很少用到这种原生的Ajax请求了。

jQuery Ajax

jQuery内部也封装了Ajax,使其更简单。
示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XMLHttpRequest</title>
</head>
<body>
</body>
<!-- jQuery中使用Ajax,要先引入jQuery文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
    console.log('----------------  get ----------------');
    
    $.ajax({
        url: "http://wthrcdn.etouch.cn/weather_mini?city=郑州",
        type: "get",
        success: function (data) {
            data = JSON.parse(data);
            console.log(data);
          }
    });
    console.log('----------------  post ----------------');
    $.ajax({
        url: "http://www.httpbin.org/post",  // 请求的url
        type: "post",  // 请求类型
        headers:{   // 携带请求头
            k1:"v1",
            k2:"v2"
        },
        data: {"name": "zhangkai", "age": 18},  // 请求携带的data
        success: function (data) { // 正确响应走这里
            console.log(data);
        },
        error: function (msg) { // 当遇到服务器400系列或者500系列的响应时,走error
            console.log('error:', msg);
          }
    });
</script>
</html>

示例

Django中Ajax和form表单登录示例

主要文件。
views.py

from django.shortcuts import render, redirect, HttpResponse
from django.http import JsonResponse

def login(request):
    """ form表单的登录视图函数 """
    if request.method == "POST":
        user = request.POST.get("username")
        pwd = request.POST.get("password")
        if user == 'zhangkai' and pwd == "123":
            return redirect('/index/')
        else:
            return render(request, 'login.html', {"username": 'zhangkai', 'password': "123", "msg": "用户名或者密码错误!!!"})
    else:
        return render(request, 'login.html', {"username": 'zhangkai', 'password': "123"})



def ajax_login(request):
    """ ajax的登录视图函数 """
    if request.method == "POST":
        user = request.POST.get("username")
        pwd = request.POST.get("password")
        print(11111, user, pwd)
        if user == 'zhangkai' and pwd == "123":
            return JsonResponse({"status_code": 200, "status_content": "login successful!!!"})
        else:
            return JsonResponse({"status_code": 201, "status_content": "用户名或者密码错误!!!"})
    else:
        return render(request, 'login.html', {"username": 'zhangkai', 'password': "123"})
def index(request):
    """ 主页 """
    return HttpResponse("http 200 ok,懒得写html页面了!!!")

urls.py

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index, name='index'),
    path('login/', views.login, name='login'),
    path('ajax_login/', views.ajax_login, name='ajax_login'),
]

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<h1>form表单形式登录</h1>
<form action="" method="post">
    {% csrf_token %}  <!-- 很重要,不能注释 -->
    <input type="text" name="username" value="{{ username }}">
    <input type="password" name="password" value="{{ password }}" >
    <input type="submit" value="form表单提交">
    <span style="color:red">{{ msg }}</span>
</form>
<br>
<h1>AJAX形式登录</h1>
<input type="text" name="username" value="zhangkai" id="user">
<input type="password" name="password" value="123" id="pwd">
<input type="button" value="ajax提交" id="btn">
<span style="color:red" id="msg"></span>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
    $("#btn").click(function () {
        var user = $("#user").val();
        var pwd = $("#pwd").val();
        $.ajax({
            url:"/ajax_login/",  // 如果是本地,可以写相对路径
            type:"post",
            // Ajax仍然受CORS影响,所以要在data中手动的携带csrf_token
            data:{"username": user, "password": pwd, "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()},
            success:function (data) {
                if(data['status_code'] == 200){
                    window.location.href = '/index/'
                }else{
                    $("#msg").text(data['status_content'])
                }
            }
        })
    })
</script>
</html>

Ajax解决跨域问题

Django + jQuery Ajax

urls.py

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('test/', views.test, name='test'),
]

前端就有这几种方案。
方案1
在ajax发送请求时,在data中带着csrf_token,不过这需要在body中提前生成token值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<button id="submit">提交</button>
{% csrf_token %}  <!-- 就这一行,csrf_token,也可以写在form表单中 -->
</body>
<!-- 首先引入 jQuery -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>
    $('#submit').click(function () {
        $.ajax({
            url: "/test/",
            type: "POST",
            data: {"key": "value", "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()},
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</html>

views.py

from django.shortcuts import render, redirect, HttpResponse

def test(request):
    if request.method == "POST":
        print(request.POST)   # <QueryDict: {'key': ['value'], 'csrfmiddlewaretoken': ['dVdfgLxEtqTkIE2RfCWRVkMISWV9HJ1dQaxmaGybtZtlnHwcCVUtzuaXvWsoQRF0']}>
        return HttpResponse('OK啦')
    return render(request, 'test.html')

方案2
这种方式用的也比较多,我们使用jQuery.ajaxSetup()函数帮我们处理。该函数用于为ajax预先设置(更改)一些默认设置。记住,它是全局生效的。如果我们在这个函数中配置关于ajax的一些设置,那么在以后的ajax请求中,都会使用该函数配置的设置。比如,我们可以在这个函数中配置解决跨域的参数。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<button id="submit">提交</button>
</body>
<!-- 首先引入 jQuery -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>

<script>
	// 预先设置ajax的某些配置,这里配置跨域参数
    $.ajaxSetup({
            data: {csrfmiddlewaretoken:'{{ csrf_token }}'}
        });
    // 后续的ajax请求,正常使用即可,无需关心跨域问题
    $('#submit').click(function () {
        $.ajax({
            url: "/test/",
            type: "POST",
            data: {"key": "value"},
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</html>

views.py

from django.shortcuts import render, redirect, HttpResponse

def test(request):
    if request.method == "POST":
        print(request.POST)   # <QueryDict: {'csrfmiddlewaretoken': ['npWLC80DvGcROnxLMsOQWjOymMhwuZyj0EgSw31avfMStq169LMsAtcNZMOLD7c6'], 'key': ['value']}>
        return HttpResponse('OK啦')
    return render(request, 'test.html')

方案3
还有一种放在request.META中,但是这种方式需要jquery.cookie.js文件搭配。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>

</head>
<body>
<button id="submit">提交</button>
</body>
<!-- 首先引入 jQuery -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<!-- 这种方式必须引入 jquery.cookie.js 文件,这里使用cdn,也可以下载到本地使用 -->
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

<script>
    $('#submit').click(function () {
        $.ajax({
            url: "/test/",
            type: "POST",
            headers: {"X-CSRFToken": $.cookie('csrftoken'), "zhangkai": 666},
            data: {"key": "value"},
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</html>

views.py

from django.shortcuts import render, redirect, HttpResponse

def test(request):
    if request.method == "POST":
        print(request.POST)   # <QueryDict: {'key': ['value']}>
        print(request.META['HTTP_COOKIE'])  # csrftoken=Vnjg1JlDmjOoMPuDbTew9kzcfkv4hP0XyCDnVEmamSoprSYYycc8NuXrSk2jqXEK; jenkins-timestamper-offset=-28800000
        print(request.META['CSRF_COOKIE'])  # Vnjg1JlDmjOoMPuDbTew9kzcfkv4hP0XyCDnVEmamSoprSYYycc8NuXrSk2jqXEK
        print(request.META['HTTP_X_CSRFTOKEN'])  # Vnjg1JlDmjOoMPuDbTew9kzcfkv4hP0XyCDnVEmamSoprSYYycc8NuXrSk2jqXEK
        return HttpResponse('OK啦')
    return render(request, 'test.html')

that's all, see also:

Django基础七之Ajax| http://www.httpbin.org/ | https://www.bootcdn.cn/jquery/ | JS XMLHttpRequest入门教程(非常详细) | w3school: XMLHttpRequest 对象 | https://developer.mozilla.org/zh-CN/docs/Glossary/AJAX | XMLHttpRequest | XMLHttpRequest Level 2 使用指南 | XMLHttpRequest和Ajax | Ajax与XMLHTTPRequest基础理解 | JavaScript之原生Ajax

posted @ 2018-07-11 18:42  听雨危楼  阅读(528)  评论(0编辑  收藏  举报