Python学习笔记Day24 - Ajax

初识Ajax

验证输入信息
悄悄地提交,不刷新页面

$('i1').click(function(){
    $.ajax({
        url: '/host',
        type: "POST",
        data: {'k1': 123,'k2': "root",'k4': JSON.stringfy({'k1': 'v'})}, // 要提交的数据
        // .stringfy() 将字典序列化成字符串
        // traditional:true                 // 使发送的data中可以接收列表数据'k3':[1,2,3]
        // data:$('#add_form').serialize(),  // 自动将form表单中的数据打包发送,上传文件看下面

        dataType:'JSON',                 // 自动将接收到的data反序列化成obj返回
        success: function(data){        // 此处data为接收到返回的httpRes信息,可传obj
            // 服务器返回信息后自动触发
            // data是服务器端返回的字符串, 如果用dataType:'JSON', 传的参数是obj对象
            // var obj = JSON.parse(data);     // json将字符串反序列化成字典  #.stringfy()序列化
            if (obj.status){
                location.reload();          // 刷新          
                location.href = "某个地址"  // 跳转
            }else{
                $('#error_msg').text(obj.error)         // 将收到的错误信息传给error_msg标签
            }
        },
        error:function(){
            ...
            //后台未接收到请求或未返回数据等未知错误
        }
    })
})
  • 其他写法:(不推荐)

      $.get(url='',data='',success='function(){}')
      $.post(url='',data='',success='function(){}')
    
  • 建议:永远让服务器端返回一个字典

      ret={'status':True,'error':None,'data':None}
      return HttpResponse(json.dumps(ret))    #json将字典序列化成字符串
    
  • ajax返回数据推荐用HttpResponse

      提交 -> url -> 函数或类中的方法
                  HttpResponse('{}')
                  render(request, 'index.html', {'name': 'v1'})
                  "<h1>{{ name }}</h1>" -->> "<h1>v1</h1>"  只能返回字符串给用户    
                  不能redirect()
      用户  <<<<<  字符串
    
  • ajax只发送数据不涉及表单时,解决csrf_token

      引入cookie,在ajax中将cookie中的csrftoken添加至请求头中
      <script src="/static/jquery.cookie.js"></script>
          $.ajax({
              ...
              headers: {"X-CSRFToken": $.cookie('csrftoken')},
              ...
              })
    

Ajax发送数据

参考博客

大部分采用XMLHttpRequest,但IE只支持ActiveXObject

原生Ajax

  • 创建XMLHttpRequest或ActiveXObject对象

      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();
      }
    

基于jQuery的Ajax

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

jQuery 不是生产者,而是大自然搬运工。
jQuery Ajax本质: XMLHttpRequest 或 ActiveXObject
注:2.+版本不再支持IE9以下的浏览器

$.ajax({
    url: '/upload_file/',
    type: 'POST',
    data: fd,
    success:function(arg,a1,a2){
        console.log(arg);
        console.log(a1);
        console.log(a2);    # a2包含一个xhr对象
    }
})

伪Ajax操作(iframe)

由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求。
服务端返回时,触发iframe的onload事件,并将数据放在iframe的#document对象中
也可自定义onload事件,使用$('#ifm1').contents()获取iframe内的标签

<form action="/ajax_json/" method="POST" target="ifm1">     # target将form与iframe绑定
    <iframe id="ifm1" name="ifm1" ></iframe>
    <input type="text" name="username" />
    <input type="text" name="email" />
    <input type="submit" onclick="sumitForm();" value="Form提交"/>
</form>

function sumitForm(){
    $('#ifm1').load(function(){
        var text = $('#ifm1').contents().find('body').text();
        var obj = JSON.parse(text);
    })
}

三种方式使用的时机

如果发送的是【普通数据】 -> jQuery,XMLHttpRequest,iframe

如果发送的是【文件】 -> iframe,jQuery(FormData),XMLHttpRequest(FormData)

文件上传(预览)

上传按钮的input框本身不能直接style修改美化,只能通过relative伪覆盖添加新的标签进行美化

上传文件三种方式:

1. iframe

兼容性好

<form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
    <iframe id="ifm1" name="ifm1" style="display: none;"></iframe>
    <input type="file" name="fafafa" onchange="changeUpalod();" />
    <input type="submit" onclick="iframeSubmit();" value="Form提交"/>
</form>

function iframeSubmit(){
    $('#ifm1').load(function(){
        var text = $('#ifm1').contents().find('body').text();
        var obj = JSON.parse(text);
        // 实现预览
        $('#preview').empty();
        var imgTag = document.createElement('img');
        imgTag.src = "/" + obj.data;
        $('#preview').append(imgTag);
    })
}

2. jQuery(FormData)

function jqSubmit(){
    // ajax上传文件必须通过FormData对象传输数据
    var formdata = new FormData();
    
    formdata.append('username', $('#username').val());
    formdata.append('psd', $('#password').val());
    formdata.append('file', $('#file')[0].files[0]);

    $.ajax({
        url: '/upload_file/',
        type: 'POST',
        headers: { "X-CSRFToken": $.cookie('csrftoken') },
        data: formdata,
        processData: false,  // 不处理数据(文件上传必须)
        contentType: false,  // 不设置内容类型,按原格式传输(文件上传必须)
        success:function(arg,a1,a2){
            console.log(arg);
            console.log(a1);
            console.log(a2);
        }
    })
}

3. XMLHttpRequest(FormData)

function xhrSubmit(){
    // $('#fafafa')[0]              // 获取input上传的文件对象
    var file_obj = document.getElementById('fafafa').files[0];  

    var fd = new FormData();        // 创建FormData对象
    fd.append('username','root');   // 添加普通数据,key-value
    fd.append('fafafa',file_obj);   // 添加文件对象,key-obj

    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/upload_file/',true);
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            // 接收完毕
            var obj = JSON.parse(xhr.responseText);
            console.log(obj);
        }
    };
    xhr.send(fd);
}

图片验证码 + Session

1. GET访问页面

-> 创建图片并返回给用户
    => 用Pillow模块创建一张图片,并在图片中写入随机字符串(封装成check_code.py模块,返回img对象和验证字符串strs)(依赖字体文件)
        img, code = creat_validate_code()
    => 将img写入内存
        stream = BytesIO()
        img.save(stream,'PNG')
    => 读取内存中的图片并显示
        data = stream.getValue()
        HttpResponse(data)
-> session存放验证码
    => 将code写入session
        request.session['CheckCode'] = code

2. POST提交数据

-> 比对验证码
    if request.session['CheckCode'].upper() == request.POST.get('check_code').upper();
        ...
-> 更换验证码
    绑定点击事件 onclick="changeCheckCode(this);"
    ths.src = ths.src + '?'     # 采用地址后面加?的方式,更换地址重新获取验证码

JSONP - 最广泛的跨域请求方式

(JSONP - JSON with Padding是JSON的一种“使用模式”),利用script标签的src属性实现跨域请求

import requests
response = request.get('http://www.baidu.com')
response = request.post('http://www.baidu.com')
# print(response.content)   # 字节格式的文本
response.encoding = 'utf-8' # 指定编码
print(response.text)        # 文本内容(经编码后的字符串)
print(response.headers)     # 响应头
print(response.cookies)     # 所有cookies

return render(request, 'req.html',{'result': response.text})

由于浏览器具有同源策略(阻止Ajax请求,但无法阻止)

JSONP使用js巧妙实现跨域请求:

  1. 创建script标签

     var tag = document.createElement('script');
    
  2. src=远程地址

     tag.src = 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403';
    
  3. 将标签添加进header,随后移除

     document.head.appendChild(tag);
     document.head.removeChild(tag);
    
  4. 返回的数据必须是js格式

     必须提前写好函数才能解析返回的js代码,可将函数名用callback参数传给url
    

JSONP只能发GET请求

利用ajax实现JSONP请求:

$.ajax({
        url: 'http://www.jxntv.cn/data/jmd-jxtv2.html',
        type: 'POST',
        dataType: 'jsonp',
        jsonp: 'callback',
        jsonpCallback: 'list'       # 传递函数名
    })
原理同上

还有CORS方式跨域请求,直接将域名加白名单

编辑框

CKEditor,UEEditor,TinyEditor,KindEditor(***)

参考博客

1.基本使用

官网下载

  • 文件夹说明

      ├── asp                         -> asp示例
      ├── asp.net                     -> asp.net示例
      ├── attached                    -> 空文件夹,放置关联文件attached
      ├── examples                    -> HTML示例
      ├── jsp                         -> java示例
      ├── lang                        -> 支持语言
      ├── license.txt                 -> License
      ├── php                         -> PHP示例
      ├── plugins                     -> KindEditor内部使用的插件
      ├── themes                      -> KindEditor主题
      ├── kindeditor-all-min.js       -> 全部JS 包含插件(压缩)
      ├── kindeditor-all.js           -> 全部JS 包含插件(未压缩)
      ├── kindeditor-min.js           -> 仅KindEditor JS(压缩)
      └── kindeditor.js               -> 仅KindEditor JS(未压缩)
    
  • HTML

      <textarea name="content" id="content"></textarea>
       
      <script src="/static/jquery-1.12.4.js"></script>
      <script src="/static/plugins/kind-editor/kindeditor-all.js"></script>
      <script>
          $(function () {
              initKindEditor();
          });
       
          function initKindEditor() {
              var kind = KindEditor.create('#content', {
                  width: '100%',       // 文本框宽度(可以百分比或像素)
                  height: '300px',     // 文本框高度(只能像素)
                  minWidth: 200,       // 最小宽度(数字)
                  minHeight: 400      // 最小高度(数字)
              });
          }
      </script>
    
  • 详细参数

http://kindeditor.net/docs/option.html

2.文件上传

  • 文件上传,多文件上传,文件空间管理

3.XSS攻击(过滤的函数或类)

下节课说...

使用kindeditor会隐藏原来的textarea标签,而如果该标签为required,提交时浏览器会报错

解决办法:

  1. form表单添加novalidate属性,但会导致所有验证都不能用,不建议

  2. 取消该标签的required

作业

主站:

http://127.0.0.1:8000/                  博客首页
http://127.0.0.1:8000/zhaofan/1.html    某人的某篇博客

个人博客:

http://127.0.0.1:8000/zhaofan.html                  某人的博客
http://127.0.0.1:8000/zhaofan/tag/python.html       某人的博客筛选
http://127.0.0.1:8000/zhaofan/catetory/mvc.html     某人的博客筛选
http://127.0.0.1:8000/zhaofan/date/2011-11.html     某人的博客筛选

个人后台管理:

http://127.0.0.1:8000/backend/base-info.html
http://127.0.0.1:8000/backend/tag.html
http://127.0.0.1:8000/backend/category.html
http://127.0.0.1:8000/backend/article.html
http://127.0.0.1:8000/backend/add-article.html
posted @ 2020-07-05 23:33  Jerome12138  阅读(217)  评论(0编辑  收藏  举报