概述

对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上。

1、传统的Web应用

2、AJAX

补充:

1、同步异步描述:

利用ajax发请求就在于它的异步方式,偷偷发送,不影响页面的任何效果;

如果采用同步发送,就没有什么意义了。

2、兼容性问题:

1)ie8以下的浏览器并没有XMLHTTPRequest对象(浏览器的对象,广义上的,是现在浏览器都支持的),所以不能发Ajax操作,这就涉及到兼容性的问题;

但早期IE有一种对象可以替代XMLHTTPRequest,他就是ActiveXObject。

2)jQuery1.x版本具有上下兼容性,2.x以上版本不支持,果断的放弃了兼容性问题;

所以,利用jQuery发Ajax请求,如果考虑兼容性问题,就需要使用1.x版本的Query,它是对ActiveXObject的上层封装。

3、拓展:

alert、XMLHTTPRequest都是属于windows的,全称是windows.;

alert()  = windows.alert()
XMLHTTPRequest()  = windows.XMLHTTPRequest()
windows['XMLHTTPRequest']

原生AJAX

Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)。

1、XmlHttpRequest对象介绍

XmlHttpRequest对象的主要方法:

a. void open(String method,String url,Boolen async)
   用于创建请求

   参数:
       method: 请求方式(字符串类型),如:POST、GET、DELETE...
       url:    要请求的地址(字符串类型)
       async:  是否异步(布尔类型)

b. void send(String body)
    用于发送请求

    参数:
        body: 要发送的数据(字符串类型)

c. void setRequestHeader(String header,String value)
    用于设置请求头

    参数:
        header: 请求头的key(字符串类型)
        vlaue:  请求头的value(字符串类型)

d. String getAllResponseHeaders()
    获取所有响应头

    返回值:
        响应头数据(字符串类型)

e. String getResponseHeader(String header)
    获取响应头中指定header的值

    参数:
        header: 响应头的key(字符串类型)

    返回值:
        响应头中指定的header对应的值

f. void abort()

    终止请求

XmlHttpRequest对象的主要属性:

a. Number readyState
   状态值(整数)

   详细:
      0-未初始化,尚未调用open()方法;
      1-启动,调用了open()方法,未调用send()方法;
      2-发送,已经调用了send()方法,未接收到响应;
      3-接收,已经接收到部分响应数据;
      4-完成,已经接收到全部响应数据;

b. Function onreadystatechange
   当readyState的值改变时自动触发执行其对应的函数(回调函数)

c. String responseText
   服务器返回的数据(字符串类型)

d. XmlDocument responseXML
   服务器返回的数据(Xml对象)

e. Number states
   状态码(整数),如:200、404...

f. String statesText
   状态文本(字符串),如:OK、NotFound...

2、跨浏览器支持

  • XmlHttpRequest
    IE7+, Firefox, Chrome, Opera, etc.
  • ActiveXObject("Microsoft.XMLHTTP")
    IE6, IE5

基于原生AJAX - Demo

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <h1>XMLHttpRequest - Ajax请求</h1>
    <input type="button" onclick="XmlGetRequest();" value="Get发送请求" />
    <input type="button" onclick="XmlPostRequest();" value="Post发送请求" />

    <script src="/statics/jquery-1.12.4.js"></script>
    <script type="text/javascript">
        // 解决原生ajax的浏览器版本兼容性问题
        function GetXHR(){
            var xhr = null;
            if(XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else{
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xhr;

        }

        function XhrPostRequest(){
            var xhr = GetXHR();
            // 定义回调函数
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 已经接收到全部响应数据,执行以下操作
                    var data = xhr.responseText;
                    console.log(data);
                }
            };
            // 指定连接方式和地址----文件方式
            xhr.open('POST', "/test/", true);
            // 设置请求头
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
            // 发送请求
            xhr.send('n1=1;n2=2;');
        }

        function XhrGetRequest(){
            var xhr = GetXHR();
            // 定义回调函数
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 已经接收到全部响应数据,执行以下操作
                    var data = xhr.responseText;
                    console.log(data);
                }
            };
            // 指定连接方式和地址----文件方式
            xhr.open('get', "/test/", true);
            // 发送请求
            xhr.send();
        }

    </script>

</body>
</html>

注意事项:

兼容性(加上下面的代码):

function GetXHR(){
            var xhr = null;
            if(XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else{
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xhr;

        }

发普通数据(字符串,或key,value类型):

实例:

urls:

# path('ajax$', views.ajax),  X  path不支持^
url('^ajax$', views.ajax),
url('^ajax_json$', views.ajax_json),

views:

################原生ajax#############
def ajax(request):
    return render(request, 'day24-app06/ajax.html')

def ajax_json(request):
    print("request.POST", request.POST) # 得到的空对象:<QueryDict: {}>,post提交传字符串类型, js需要加入请求头
    # xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
    # < QueryDict: {' pwd': ['akaedu'], 'user': ['uson']} >

    ret = {'status': True, 'data': request.POST.get('user')} # 返回给前端
    import json
    return HttpResponse(json.dumps(ret))
    # HttpResponse继承基类:HttpResponseBase-->status, reason='Not Found'
    # return HttpResponse(json.dumps(ret), status=200, reason='Not Found')返回更多的数据

ajax.html(未考虑兼容性问题):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" value="原生Ajax" onclick="Ajax1();" />
    <script>
        function Ajax1() {
            // 过程分析:
            // 创建XMLHttpRequest对象
            // open(发送方式,发送地址,同步/异步发送)
            // send("数据1=value1; 数据2=value2")

            var xhr = new XMLHttpRequest(); // 无ie下的兼容性
            // get方式
            // xhr.open('get', '/cohui/ajax_json', true); 不写,默认是true
            // xhr.send({'code': 304, 'status': true}); X
            // xhr.send('name=uson; pwd=123');

            // post方式, 后台接收
            // 先忽略csrf_token
            xhr.open('post', '/cohui/ajax_json', true);

            // 还可以设置添加请求头
            xhr.setRequestHeader('k1', 'v1');

            // post 提交字符串类型,必须写上下面的请求头
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
            xhr.send('user=uson; pwd=akaedu');

            // 前端接收返回回来的数据
            // 当readystate值发生了变化,就会执行下面的函数,现在,给函数执行加入一个条件:接收完成打印信息
            xhr.onreadystatechange = function(){  // 相当于一个回调函数
              if(xhr.readyState == 4){
                  // 后台已经接收到全部请求数据,执行以下操作
                  var data = xhr.responseText;       // 获取数据
                  // console.log(data);    // {"status": true, "data": "uson"}
                  // 字典,js不能取到,需要转成对象
                  data = JSON.parse(data);
                  console.log(data);
                  console.log(data.data);  // uson
              }
            };

        }
    </script>
</body>
</html>

ajax.html(考虑兼容性问题):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="button" value="原生Ajax" onclick="Ajax1();" />
    <script>
        // 跨浏览器支持:https://www.cnblogs.com/wupeiqi/articles/5703697.html
        // 解决IE低版本浏览器兼容性问题
        function getXHR(){
            var xhr = null;
            if(XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else{
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xhr;
        }

        function Ajax1() {
            // 过程分析:
            // 创建XMLHttpRequest对象
            // open(发送方式,发送地址,同步/异步发送)
            // send("数据1=value1; 数据2=value2")

            // 增加兼容性:
            var xhr = getXHR();

            // get方式
            // xhr.open('get', '/cohui/ajax_json', true); 不写,默认是true
            // xhr.send({'code': 304, 'status': true}); X
            // xhr.send('name=uson; pwd=123');

            // post方式, 后台接收
            // 先忽略csrf_token
            xhr.open('post', '/cohui/ajax_json', true);

            // 还可以设置添加请求头
            xhr.setRequestHeader('k1', 'v1');

            // post 提交字符串类型,必须写上下面的请求头
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
            xhr.send('user=uson; pwd=akaedu');

            // 前端接收返回回来的数据
            // 当readystate值发生了变化,就会执行下面的函数,现在,给函数执行加入一个条件:接收完成打印信息
            xhr.onreadystatechange = function(){  // 相当于一个回调函数
              if(xhr.readyState == 4){
                  // 后台已经接收到全部请求数据,执行以下操作
                  var data = xhr.responseText;       // 获取数据
                  // console.log(data);    // {"status": true, "data": "uson"}
                  // 字典,js不能取到,需要转成对象
                  data = JSON.parse(data);
                  console.log(data);
                  console.log(data.data);  // uson
              }
            };

        }
    </script>
</body>
</html>

小结:

1、基于原生Ajax发POST请求,如果是普通数据类型,一定要加上请求头,否则后台不认识,无法解析send中的内容数据(字符串或key,value类型)。

xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');

上传文件(特殊类型的数据):

实例:

urls:

#############基于XML实现文件上传#############
url('^upload$', views.upload),

views:

#############基于XML实现文件上传#############
def upload(request):
    if request.method == "POST":
        username = request.POST.get('username')
        fafile = request.FILES.get('fafile')
        print(fafile, username)  # 8月续费计划.xlsx uson

        # 循环接收文件chunks
        import os
        upload_path = os.path.join('static/upload/' + fafile.name)
        with open(upload_path, 'wb') as f:
            for item in fafile.chunks():   # 也可以直接用fafile迭代
                f.write(item)

        # return redirect('/cohui/upload')  # 下面方法:图片预览,指定路径

        # upload必须放进静态目录下
        ret = {'path': upload_path}
        import json
        return HttpResponse(json.dumps(ret))
    return render(request, 'day24-app06/upload.html')

upload.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .main{
            width: 100px;
            height: 40px;
            background-color: dodgerblue;
            color: white;

            position: relative;

            margin-bottom: 20px;
        }
        .file{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            /* 让原生的上传按钮在文字上面z-index,并使他的透明度opacity为0,即隐藏 */
            opacity: 0;
            z-index: 100;

            cursor: pointer;
        }
        .upload{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            z-index: 90;

            text-align: center;
            line-height: 40px;
            /*cursor: pointer;*/
        }
    </style>
</head>
<body>
    <div class="main">
        <input id="fafa" class="file" type="file" name="fafa" />
        <a class="upload">上传</a>
    </div>
    <input type="button" value="XHR文件上传提交" onclick="xhrAjax();">
    <div class="picPreview"></div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        // XML 原生ajax上传
        function xhrAjax() {
            // 获取文件对象,类似于val,text
            var file_obj = document.getElementById('fafa').files[0]; // 第一个文件
            // 发送的是对象,send() 不能直接发送对象类型

            var fd = new FormData();  // 相当于form表单对象
            fd.append('username', 'uson');
            fd.append('fafile', file_obj);   // 对象加进去,这时无需设置请求头了

            var xhr = new XMLHttpRequest();  // 实例化
            xhr.open('post', '/cohui/upload', true);  // 设置提交到的url
            xhr.onreadystatechange = function () {
                if(xhr.readyState == 4){
                    // 接收完毕, 获取数据并转换成对象
                    var obj= JSON.parse(xhr.responseText);

                    // 图片预览
                    // 每次预览前清空预览缓存
                    $('.picPreview').empty();
                    // 创建img标签  指定src路径属性
                    var imgTag = document.createElement('img');
                    imgTag.src = '/' + obj.path;
                    $('.picPreview').append(imgTag);
                }
            };

            //xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');  无需设置请求头

            // csrf_token的添加
            xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));   // 依赖于jquery.cookie.js

            xhr.send(fd);
        }
    </script>
</body>
</html>

 小结:

1、由于send不能直接发送对象obj,只能发送字符串类型,所以上传文件需要用到新知识:Formdata方法,不支持低版本的IE浏览器;

var fd = new FormData();    // 相当于form表单对象
      fd.append('username', 'uson');
      fd.append('fafile', file_obj);

xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));   // 依赖于jquery.cookie.js

xhr.send(fd);   // 不用设置下面的那个请求头了
//xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');

jQuery Ajax

jQuery其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能。

  • jQuery 不是生产者,而是大自然搬运工。
  • jQuery Ajax本质 XMLHttpRequest 或 ActiveXObject 

注:2.+版本不再支持IE9以下的浏览器

jQuery Ajax 方法列表

jQuery.get(...)
所有参数:
     url: 待载入页面的URL地址
    data: 待发送 Key/value 参数。
 success: 载入成功时回调函数。
dataType: 返回内容格式,xml, json,  script, text, html


jQuery.post(...)
所有参数:
     url: 待载入页面的URL地址
    data: 待发送 Key/value 参数
 success: 载入成功时回调函数
dataType: 返回内容格式,xml, json,  script, text, html


jQuery.getJSON(...)
所有参数:
     url: 待载入页面的URL地址
    data: 待发送 Key/value 参数。
 success: 载入成功时回调函数。


jQuery.getScript(...)
所有参数:
     url: 待载入页面的URL地址
    data: 待发送 Key/value 参数。
 success: 载入成功时回调函数。


jQuery.ajax(...)

部分参数:

        url:请求地址
       type:请求方式,GET、POST(1.9.0之后用method)
    headers:请求头
       data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
      async:是否异步
    timeout:设置请求超时时间(毫秒)

 beforeSend:发送请求前执行的函数(全局)
   complete:完成之后执行的回调函数(全局)
    success:成功之后执行的回调函数(全局)
      error:失败之后执行的回调函数(全局)


    accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
   dataType:将服务器端返回的数据转换成指定类型
                   "xml": 将服务器端返回的内容转换成xml格式
                  "text": 将服务器端返回的内容转换成普通文本格式
                  "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
                "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
                  "json": 将服务器端返回的内容转换成相应的JavaScript对象
                 "jsonp": JSONP 格式
                          使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数

                  如果不指定,jQuery 将自动根据HTTP包MIME信息返回相应类型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string

 converters: 转换器,将服务器端的内容根据指定的dataType转换类型,并传值给success回调函数
         $.ajax({
              accepts: {
                mycustomtype: 'application/x-some-custom-type'
              },

              // Expect a `mycustomtype` back from server
              dataType: 'mycustomtype'

              // Instructions for how to deserialize a `mycustomtype`
              converters: {
                'text mycustomtype': function(result) {
                  // Do Stuff
                  return newresult;
                }
              },
            });

基于jQueryAjax - Demo

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="button" onclick="XmlSendRequest();" value='Ajax请求' />
    </p>


    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'GET',
                dataType: 'text',
                success: function(data, statusText, xmlHttpRequest){  // 如果不想要它默认返回的数据,可以用xmlHttpRequest对象自定制,.responseText等方法
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>

发普通数据(字符串,或key,value类型):

urls/views/html:

这里不做重述(忘记了?

上传文件(特殊类型的数据):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .main{
            width: 100px;
            height: 40px;
            background-color: dodgerblue;
            color: white;

            position: relative;

            margin-bottom: 20px;
        }
        .file{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            /* 让原生的上传按钮在文字上面z-index,并使他的透明度opacity为0,即隐藏 */
            opacity: 0;
            z-index: 100;

            cursor: pointer;
        }
        .upload{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            z-index: 90;

            text-align: center;
            line-height: 40px;
            /*cursor: pointer;*/
        }
    </style>
</head>
<body>
    <div class="main">
        <input id="fafa" class="file" type="file" name="fafa" />
        <a class="upload">上传</a>
    </div>
    <!-- 方式1 form上传 -->
    <!-- 跳过 -->

    <input type="button" value="Jquery文件上传提交" onclick="jqSubmit();">
    <div class="picPreview"></div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        // jquery上传
        function jqSubmit() {
            var file_obj = document.getElementById('fafa').files[0];
            var fd = new FormData();  // 相当于form表单对象
            fd.append('username', 'uson');
            fd.append('fafile', file_obj);

            $.ajax({
                url: '/cohui/upload',
                type: 'POST',
                headers: {'X-CSRFtoken': $.cookie('csrftoken')},
                data: fd,  // 字符串类型

                // TypeError: Illegal invocation, 加上下面的两行
                processData: false,  //tell jQuery not to process the data不对数据中的对象进行格式转换
                contentType: false,  // tell jQuery not to set contentType 不序列化json数据
                // 分析:
                // processData:默认为true,发送的数据将被转换为对象(从技术角度来讲并非字符串)以配合默认内容类型
                // contentType:“application/json”  true必须是json数据, 'xx','oo' 非json数据,所以false

                success: function (args, a1, a2) {
                    // console.log(args);
                    // console.log(a1); // success
                    console.log(a2); // 原生对象

                    // 图片预览
                    // 每次预览前清空预览缓存
                    $('.picPreview').empty();
                    // 创建img标签  指定src路径属性
                    var imgTag = document.createElement('img');
                    imgTag.src = '/' + obj.path;
                    $('.picPreview').append(imgTag);
                }

            });
        }
    </script>
</body>
</html>

“伪”AJAX

由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求。

1、load

<!DOCTYPE html>
<html>

    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>

        <div>
            <p>请输入要加载的地址:<span id="currentTime"></span></p>
            <p>
                <input id="url" type="text" />
                <input type="button" value="刷新" onclick="LoadPage();">
            </p>
        </div>


        <div>
            <h3>加载页面位置:</h3>
            <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe>
        </div>


        <script type="text/javascript">

            window.onload= function(){
                var myDate = new Date();
                document.getElementById('currentTime').innerText = myDate.getTime();

            };

            function LoadPage(){
                var targetUrl =  document.getElementById('url').value;
                document.getElementById("iframePosition").src = targetUrl;
            }

        </script>

    </body>
</html>

发普通数据(字符串,或key,value类型):

urls:

#################伪ajax##############
url('^iframe', views.iframe),

views:

#################伪ajax##############
def iframe(request):
    if request.method == "POST":
        import time
        time.sleep(3)
        # ajax提交数据后,等待后台数据回复返回后,才会加载到iframe中
        # 所以,可以通过onload来获取iframe返回的时机,从而获取数据

        ret = {'status': True, 'data': request.POST.get('username')}  # 返回给前端
        import json
        return HttpResponse(json.dumps(ret))
    return render(request, 'day24-app06/iframe.html')

html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/cohui/iframe" method="post" target="ifm">
        {% csrf_token %}

        <!-- iframe的name属性与form的target属性相互关系:form提交表单数据到iframe中,页面不刷新,其他内容不改变 -->
        <!-- <iframe name="ifm" src="http://www.cohui.top"></iframe> -->

        <!-- 方式1
        <iframe name="ifm" onload="ifr();"></iframe> -->

        <!-- 方式2: 给submit一个点击事件,再去获取iframe的加载事件,不报错 -->
        <iframe name="ifm" id="ifm"></iframe>  <!-- #document -->

        <input type="text" name="username" >
        <input type="text" name="email" >
        <input type="submit" value="Form提交" onclick="ifrm();" >
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        // 方式1:
        function ifr() {
            console.log(123);
            // 从上到下执行,先会找到 ifr()这个函数,但,这个函数在未提交前,还没执行呢,提前加载自然报错
            // Uncaught ReferenceError: ifr is not defined at HTMLIFrameElement.onload
            // 所以这种方式不太好
        }

        // 方式2;
        function ifrm() {
            // 获取iframe对象
            console.log(12); // 点击提交后,立即打印
            $('#ifm').load(function(){   // 不是onload (onload是一个事件),是load (load是一个函数)
                // 获取数据
                console.log(13); // load:用来接收返回的数据,后台有数据返回,才会执行这个函数
                var doc = $('#ifm').contents();
                console.log(doc);  // jQuery.fn.init [document, prevObject: jQuery.fn.init(1), context: document]
                var data = doc.find('body').text();
                console.log(data);  // {"status": true, "data": "123"}
                var obj = JSON.parse(data);
                console.log(obj);  // 转成对象
            });
        }
    </script>
</body>
</html>

上传文件(特殊类型的数据):

urls:

url('^upload$', views.upload),

views:

##################基于XML实现文件上传################
def upload(request):
    if request.method == "POST":
        username = request.POST.get('username')
        fafile = request.FILES.get('fafile')
        print(fafile, username)  # 8月续费计划.xlsx uson

        # 循环接收数据chunks
        import os
        upload_path = os.path.join('static/upload/' + fafile.name)
        with open(upload_path, 'wb') as f:
            for item in fafile.chunks():
                f.write(item)

        # return redirect('/cohui/upload')  # 图片预览,指定路径

        # upload必须放进静态目录下
        ret = {'path': upload_path}
        import json
        return HttpResponse(json.dumps(ret))
    return render(request, 'day24-app06/upload.html')

html(直接预览上传):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .main{
            width: 100px;
            height: 40px;
            background-color: dodgerblue;
            color: white;

            position: relative;

            margin-bottom: 20px;
        }
        .file{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            /* 让原生的上传按钮在文字上面z-index,并使他的透明度opacity为0,即隐藏 */
            opacity: 0;
            z-index: 100;

            cursor: pointer;
        }
        .upload{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            z-index: 90;

            text-align: center;
            line-height: 40px;
            /*cursor: pointer;*/
        }
    </style>
</head>
<body>
    <div class="main">
        <input id="fafa" class="file" type="file" name="fafa" />
        <a class="upload">上传</a>
    </div>
    <!-- 方式1 form上传 -->
    <!-- 跳过 -->

    <!-- iframe 伪ajax上传 -->
    <form action="/cohui/upload" method="post" target="ifm" enctype="multipart/form-data">
        {% csrf_token %}
        <iframe name="ifm" id="ifm" style="display: none;"></iframe>  <!-- #document -->
        // <input type="file" name="fafile" onchange="changeSubmit(this);" >绑定事件也是可以的==》function changeSubmit(ths) {}  <!--第二种-->
        <input type="file" name="fafile" >   <!--第一种--> ==> $('input[name="fafile"]').change(function () {})
    </form>
    <div class="picPreview"></div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        // iframe 伪ajax上传, 不点提交按钮,直接预览上传
        $('input[name="fafile"]').change(function () {  // 不能用onchange,因为它不是函数// 先绑定一个onload事件
            // 再form submit()
            $('#ifm').load(function () {
               // 加载框架,获取内容
               console.log(456);

               var data = $(this).contents().find('body').text();
               var obj = JSON.parse(data);

               // 预览前清空内容
               $('.picPreview').empty();
               // 图片预览
               var imgTag = document.createElement('img');
               imgTag.src = '/' + obj.path;
               $('.picPreview').append(imgTag);
            });
            // $(ths).submit();  // this --> file的input对象   X
            console.log(123);   // 先123,后台返回数据才456
            $('form').submit();
        })
    </script>
</body>
</html>

html(提交上传):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .main{
            width: 100px;
            height: 40px;
            background-color: dodgerblue;
            color: white;

            position: relative;

            margin-bottom: 20px;
        }
        .file{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            /* 让原生的上传按钮在文字上面z-index,并使他的透明度opacity为0,即隐藏 */
            opacity: 0;
            z-index: 100;

            cursor: pointer;
        }
        .upload{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;

            z-index: 90;

            text-align: center;
            line-height: 40px;
            /*cursor: pointer;*/
        }
    </style>
</head>
<body>
    <div class="main">
        <input id="fafa" class="file" type="file" name="fafa" />
        <a class="upload">上传</a>
    </div>

    <!-- iframe 伪ajax上传 -->
    <form action="/cohui/upload" method="post" target="ifm" enctype="multipart/form-data">
        {% csrf_token %}
        <iframe name="ifm" id="ifm" style="display: none;"></iframe>  <!-- #document -->
        <input type="file" name="fafile" />

        <input type="submit" value="Iframe提交" onclick="iframeSubmit();" />
    </form>
    <div class="picPreview"></div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        // iframe 伪ajax上传  +  图片预览
        function iframeSubmit() {
            // 提交到iframe中,有一个load加载过程,后台什么时候返回数据,什么时候加载

            $('#ifm').load(function () {  // 后台返回数据就加载

                var data = $(this).contents().find('body').text();
                var obj = JSON.parse(data);

                console.log(obj.path);    // upload/win10快捷键.jpg

                // 图片预览
                // 每次预览前清空预览缓存
                $('.picPreview').empty();

                // 创建img标签  指定src路径属性
                var imgTag = document.createElement('img');
                imgTag.src = '/' + obj.path;
                $('.picPreview').append(imgTag);

            })
        }
    </script>
</body>
</html>

小结:

1、提交表单共有4种方式:

1)form提交(刷新页面)

2)原生Ajax方式提交(不刷新页面)

3)jQuery方式提交(不刷新页面)

4)伪Ajax方式提交(不刷新页面)

2、上传文件(对象类型)特殊类型的数据,如何选择上述Ajax的几种方式?

原生Ajax方式提交和jQuery方式提交==>都依赖于FormData()类,而FormData对于IE低版本浏览器又不兼容;iframe支持所有浏览器。

所以使用的优先级比较:iframe > jQuery(FormData) > XMLHttpRequest(FormData)

3、普通类型(字符串、key,value)的数据,如何选择上述Ajax的几种方式?

原生Ajax方式提交和jQuery方式提交==>都依赖于FormData()类,而FormData对于IE低版本浏览器又不兼容;iframe支持所有浏览器。

所以使用的优先级比较:jQuery(FormData) > XMLHttpRequest(FormData) > iframe

4、iframe:里面包含的是#document,即一个上下文或空间管理,嵌套html,用.text()无法获取到数据,这里用到的是:contents()方法获取内容;

$(...).contents().find('body').text();

5、原生Ajax设置csrf的请求头方式:

xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));   // 依赖于jquery.cookie.js

跨域AJAX

查看详情

序列化

关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。

1、serializers

from django.core import serializers

ret = models.BookType.objects.all()

data = serializers.serialize("json", ret)

2、json.dumps

import json

#ret = models.BookType.objects.all().values('caption')
ret = models.BookType.objects.all().values_list('caption')

ret=list(ret)

result = json.dumps(ret)

由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

import json
from datetime import date
from datetime import datetime

class JsonCustomEncoder(json.JSONEncoder):

    def default(self, field):

        if isinstance(field, datetime):
            return o.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field, date):
            return o.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, field)

# ds = json.dumps(d, cls=JsonCustomEncoder)

后记:

form表单提交,页面肯定会刷新,ajax无法跳转
None:没有长度==>len()

Ipv4与Ipv6的认识:

Ipv4:32位,分4段:每段8位(0-255):192.168.1.6
Ipv6:128位,分8段:FE80::DE4F(共8段,中间全是0可以省略不写::)

html模板语言中的计数序号问题:

{% for row in user_list%}
    {{forloop.counter}}       从1开始计数
    {{forloop.counter0}}     从0开始计数
    {{forloop.revcounter}}   倒序
    {{forloop.revcounter0}} 倒序
    {{forloop.last}}            是否是最后一次循环(返回true)
    {{forloop.first}}            是否是第一个循环
    {{forloop.parentloop}}  用于嵌套循环,返回上一个循环的值
{% endfor%}

循环事件里面不能用id选择器(不能重复),要用class选择器

ajax打包数据发送到后台:

找到form标签==>$().serialize()====》data,会把整个form里面的值发到后台。

Ajax的返回问题:

Ajax的后台返回return 只能是HttpResponse或render(render返回html,字符串取值麻烦,列表、字典类的数据类型反序列化成对象,取值方便),但不可以是redirect,因为Ajax无法跳转页面

建议:永远返回一个字典,取值容易。

403 Forbidden (CSRF token missing or incorrect解决办法:

https://www.cnblogs.com/randomlee/p/10069061.html

12-31 16:35
查看更多