Python3基础之学习笔记(十五)-Ajax-文件上传-图片验证码

1. Django

1.1 Ajax

1.1.1 Ajax简介

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,可以指定json),相对于Form表单而言的,提交时可以偷偷向后台发数据,页面不刷新;

2大特点:

  1. 和server端异步交互
  2. 偷偷向server端发送数据,页面

和form、a标签的区别:

ajax、form、a标签都可以基于HTML页面向server端发送request,

但本质区别是form、a标签一般向server索要的是页面,而ajax则是字符串数据。

Jquery和Ajax关系:

Jquery没有Ajax功能,它之所以可以调用Ajax向服务端提交数据,是因为Jquey封装了原生Ajax的代码

使用原生Ajax的优势:

使用Ajax直接使用JS的XMLHttp Request对象, 无需引入Jquery了。这样响应客户端携带信息量减少,可节省流量。

1.1.2 原生Ajax

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

XmlHttpRequest对象介绍

XmlHttpRequest对象的主要方法:

a. void open(String method,String url,Boolen async)
   用于创建请求
 
   参数:
       method: 请求方式(字符串类型),如:POSTGETDELETE...
       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
   状态码(整数),如:200404...
 
f. String statesText
   状态文本(字符串),如:OK、NotFound...

实例

views.py

def ajax(request):
    return render(request,'ajax.html')
def ajax_json(request):
    from django.http import JsonResponse
    if request.method=='GET':
        return JsonResponse({'name':'小张','age':18})
    if request.method=='POST':
        name=request.POST.get('name')
        age=request.POST.get('age')
        print(name)
        print(age)
        return JsonResponse({'name':name,'age':age})

ajax.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajaxtitle>
head>
<body>
<input type="button" value="原生ajax" onclick="ajaxl();">
<script>
    {#跨浏览器支持#}
    function getXHR() {
        var xhr=null;
        if(XMLHttpRequest){
            xhr=new XMLHttpRequest();
        }
        else {
            xhr=new ActiveXObject('Microsoft.XMLHTTP');
        }
        return xhr;
    }
    function ajaxl() {
        var xhr=getXHR();
        {#xhr.open('GET','/ajax_json',true);#}
        xhr.open('POST','/ajax_json',true);
        xhr.onreadystatechange=function () {
            if(xhr.readyState==4){
                //数据接收完毕
                var obj=JSON.parse(xhr.responseText);
                console.log(obj);
            }
        }
        {#POST请求必须设置这个请求头#}
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
        xhr.send('name=张三;age=35')
    }
script>
body>
html>

1.1.3 jquery的ajax

function ajax_jq() {
        $.ajax(
            {
                url:'/ajax_json',
                type:'POST',
                {# traditional:一般是我们的data数据有数组时会用到 #}
                traditional:false,
                data:{'name':'张三','age':'35'},
                {#  ----------------- ajax的回调函数----------------------#}
                {#       1、server端response 200成功,执行的回调函数#}
                success:function (data) {
                        data=JSON.parse(data)
                        console.log(typeof data)},
                {#      2、server端 response错误,执行的回调函数 #}
                error:function () {
                        console.log(arguments)
                        alert(123) },
                {#      3、无论server端返回的结果如何,都会执行的回调函数#}
                complete:function () {
                        alert(321)  },
                {#      4、根据server端返回的状态码,执行的回调函数#}
                statusCode:{
                '403':function () {alert(403)},
                '503':function () {alert(503)}}
          })
    }

views.py

def ajax_json(request):
    from django.http import JsonResponse
    if request.method=='GET':
        return JsonResponse({'name':'小张','age':18})
    if request.method=='POST':
        name=request.POST.get('name')
        age=request.POST.get('age')
        print(name)
        print(age)
        JsonResponse.status_code=503
        return JsonResponse({'name':name,'age':age})

1.1.4 伪Ajax

所谓伪装Ajax操作就是不利于任何Ajax,利于其他技术向后台发送数据,这个其他的技术要从 iframa标签说起

<form action="/ajax_json" method="post" target="ifm">
        <iframe id='ifm' name="ifm" >iframe>
        <input type="text" name="username">
        <input type="text" name="age">
        <input type="submit" onclick="sumbitForm();" value="form提交">
    form>
<script>
function sumbitForm(){
        $('#ifm').load(function () {
            var con=$('#ifm').contents().find('body').text();
            console.log(con);
        });
    }
script>

1.1.5 Ajax选择

上传方法总结

上传文件—>iframe+input(伪造ajax)

上传数据---->Jquery、XMLHttpRespose(原生ajax)

图片预览功能实现思路:

1、上传图片到服务端

2、服务端返回一个URL到客户端

3、客户端再去通过img标签src服务端的返回的URL地址

1.2 文件上传

原生ajax文件上传

{% extends 'base.html' %}
{% block title %}ajax{% endblock %}
{% block content %}
    <div class="container" style="margin-top: 30px;">
        <div class="col-xs-12 col-sm-4 col-md-4">
            <div class="file-container"
                 style="display:inline-block;position:relative;overflow: hidden;vertical-align:middle">
                <button class="btn btn-success fileinput-button" type="button">上传button>
                <input type="file" id="jobData" onchange="loadFile(this.files[0])"
                       style="position:absolute;top:0;left:0;font-size:34px; opacity:0">
            div>
            <span id="filename" style="vertical-align: middle">未上传文件span>
            <input class="btn btn-outline-primary" type="button" value="提交" onclick="sumbitFile();">input>
        div>
 
    div>
{% endblock %}
{% block custom_js %}
    <script >
        function loadFile(file) {
            $("#filename").html(file.name);
        }
        function sumbitFile() {
           var file_obj=document.getElementById('jobData').files[0];
           var fd=new FormData();
           fd.append('upload_file',file_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);
        }
    script>
{% endblock %}

jQuery提交

function sumbitFileJquery() {
            var file_obj = $('#jobData')[0].files[0];
            var fd = new FormData();
            fd.append('upload_file', file_obj);
            $.ajax({
                url: '/upload_file',
                type: 'POST',
                contentType: false,
                {#告诉Jquery不要对请求头做特殊处理,因为formDta已经把数据封装好了#}
                processData: false,
                data: fd,
                success: function (args) {
                   console.log(args)
                }
            })
        }

iframe+form标签伪造ajax操作(兼容性更好)


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>伪造Ajax上传title>
head>
<body>
<h1>伪造Ajax上传h1>
<p><input type="file" name="k1">p> <p>