百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

Ajax发送POST请求

citgpt 2024-10-24 16:20 15 浏览 0 评论

一、 Ajax 介绍

Ajax 就是可以让页不刷新的情况下,给服务器发送 HTTP 请求并获取到数据。


通过编写 JavaScript 代码,还可以把获取到的数据展示在当前页面上。


二、 jQuery 封装的 Ajax

语法格式


$.ajax({

    /* url 地址可以是 /get-json/ 的方式

    *  也可以是 http://www.qfedu.com/get-json/ 的方式

    */

    url: 'url 地址',

    type: 'GET/POST',

    dataType: 'json',

    success: function(res){

        // 成功处理逻辑

     },

    error: function(res){

        // 错误时处理逻辑

        }

            });

img


Django POST 方法提交表单,必须面临一个问题,那就是 CSRF_TOKEN

CSRF(Cross-site request forgery跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

Django 中自带了这个防止CSRF攻击的功能。

GET 请求不需要 CSRF 认证,POST 请求需要正确认证才能得到正确的返回结果。


解决的思路是:

在前端代码的 form 表单内写上 {% csrf_token %},

用来接收 Django 返回的 csrf_token 的值

{% csrf_token %} 会在表单中生一个隐藏的 input 标签

<input type="hidden" name="csrfmiddlewaretoken" value="EAYZaWHO8g7ZtI4N2xPzKCvxj94sCNPnsYTCLQpQWudH38iK0vHoyYf8NtRBjcRP">

\2. 想办法把此标签的 key 和 value 作为首层数据发送到后端,Django 后端会自动获取验证


获取到 csrf_token 的 key 和 value 的方法有一下几种

从页面中的源码中获得。

当第一次请求后不论验证结果如何,前端页面在写上 {% csrf_token %}

的前提下,就会有个隐藏的 input 标签,复制他的 name 属性的值就是 key, 复制 value属性的值就是我们要的 value

从cookie 中得到。

利用 javascript.cookie.js 可以从 cookie 中得到。

javascript.cookie.js 下载地址

就在其源码的 src 目录下 。


使用方法:

// 引入

<script src="/static/jquery.cookie.js"></script> 

<script>

// 获取到值

var token_val = $.cookie('csrftoken')

</script>

从 form 表单中自动获取

   <form >

      {% csrf_token %}

      <input type="file" />

      <input type="text" name="one" value="FormData_one"/>

      <input type="text" name="two" value="FormData_two"/>

      <button >提交</button>

  </form>

  <script>

  $("#Ajax_FD_submit").serialize()); 

  </script>

serialize() 会获取到在 form 标签内的所有数据,并进行序列化;这种适合提交数据比较多的情况

利用 Django 的模版语言

 {{ csrf_token }} // 它就是 csrf_token 的值

注意一点: csrf_tken 的数据向后台提交的时候,必须放在首层,不要在嵌套到其他数据类中了

因为 Django 会从 GET 或 POST 的数据体内寻找固定的 csrf_token key 的值来验证。

下面来说怎么结合以上的方法,具体实现 Ajax 提交数据并进行 csrf_token 认证

第一种: 结合 JavaScript 的 FormDate 类,实现 Ajax 提交

简单介绍

实现的功能:可以提交表单中的数据和文件。

缺点:目前兼容性还不太好,因为 FormDate 这个类是比较新的特性,IE8 及一下版本的浏览器不支持。

相信随着时间的推移,这种方法会逐渐称为主流,必须掌握。

FormData

FormData 是 JavaScript 的一个新特性,他可以让你对其进行实例化出一个对象,这个对象就像是一个盒子、容器,你可以往里面填充数据,填充的方法就像是 Python 中的列表一样。目前我所知道的是每次只可以添加一对,这对儿数据就是 'key','value' 的形式。


实现

前端Ajax发送数据的代码:

    <h1>Ajax上传文件</h1>

    <form >

        {% csrf_token %}

        <input type="file" />

        <input type="text" name="one" value="FormData_one"/>

        <input type="text" name="two" value="FormData_two"/>

        <button >Ajax提交</button>

    </form>

    <script>

    $(function () {

        $('#ajax_btn').click(function () {

            var fmd_obj = new FormData(); // 实例化一个对象

            // 向对象中添加数据,格式:fmd_obj.append('key','value')

            fmd_obj.append('sub_file_name', document.getElementById('sub_file').files[0]);

            fmd_obj.append('my_list', ['a','b']); //每次都可以向这个对象中添加一个数据

            fmd_obj.append('my_key','my_value');

            fmd_obj.append('csrfmiddlewaretoken','{{ csrf_token }}') // 解决认证问题

            fmd_obj.append('data',$("#Ajax_FD_submit").serialize());


            $.ajax({

                url: "/ajax-upload/",

                type: 'POST',

                data: fmd_obj,

                processData: false, // tell jQuery not to process the data

                contentType: false, // tell jQuery not to set contentType

                success:function (arg) {

                    console.log(arg);

                },

            });

            return false; // 最好返回false,因为如果按钮类型是submit,或者是 button 标签,

                          // 则表单自己又会以 GET 的方式再提交一次;返回false阻止表单再次提交

        });

    });

</script>

后端接收数据的代码

def ajax_upload(request):

    """

    接收前端 Ajax 发送过来的数据和文件

    :param request:

    :return:

    """

    import os,json

    response = BaseReponse()

    try:

        print('reqpost数据>>:', request.POST)

        print('reqfile数据>>:', request.FILES)

        file_obj = request.FILES.get('sub_file_name')

        print('接收到的文件>>:', file_obj)

        print('参数key one 的值>>:', request.POST.get('one'))

        print('参数key two 的值>>:', request.POST.get('two'))


        # file_dir = os.path.join(settings.BASE_DIR, 'img') # 设置接收文件的绝对路径

        # print("文件保存的绝对路径>>:", file_dir)

        """下面的是把接收到的文件保存到服务器上"""

        file_path = os.path.join('static', file_obj.name) # 组合文件的完整路径

        new_file_obj = open(file_path, 'wb')

        [new_file_obj.write(chunk) for chunk in file_obj.chunks()]

        new_file_obj.close()


        """设置一下返回信息和状态"""

        response.status = True

        response.data = file_path

    except Exception as e:

        response.status = False

        response.error = "上传失败"


    return HttpResponse(json.dumps(response.__dict__))

后端得到的数据

reqpost数据>>: <QueryDict: {'my_list': ['a,b'], 'csrfmiddlewaretoken': ['EAYZaWHO8g7ZtI4N2xPzKCvxj94sCNPnsYTCLQpQWudH38iK0vHoyYf8NtRBjcRP'], 'my_key': ['my_value'], 'data': ['csrfmiddlewaretoken=EAYZaWHO8g7ZtI4N2xPzKCvxj94sCNPnsYTCLQpQWudH38iK0vHoyYf8NtRBjcRP&one=FormData_one&two=FormData_two']}>

reqfile数据>>: <MultiValueDict: {'sub_file': [<InMemoryUploadedFile: 乖巧中透漏这悲伤.png (image/png)>]}>

接收到的文件>>: 乖巧中透漏这悲伤.png

参数key one 的值>>: None

参数key two 的值>>: None

因为 .serialize() 得到的是 form 表单内的所有数据,所以在内层数据中也会有个 csrf_token

第二种: 利用 Form 和 ifram 实现"伪"Ajax 提交

简单介绍

实现的功能:可以提交表单和文件;目前业界比较流行

关键点

form 标签要定义一个 target 属性,其值必须与 ifram 标签的 name 属性的值相同


实现

前端"伪"Ajax发送数据的代码:

<h1>"伪"Ajax操作</h1>

//可以同时提交文件和数据

<div>

    <form action="/ajax-upload/" method="POST" enctype="multipart/form-data" target="ifr">

        {% csrf_token %}

        <input type="file" name="sub_file_name" />

        <input type="text" name="one" value="iframe_one"/>

        <input type="text" name="two" value="iframe_two"/>

    </form>


    <iframe name="ifr"style="display: none"></iframe>


    // 用于展示预览的图片

    <div ></div>

</div>

<script>

    // "伪"Ajax操作,自动上传

    // 标签的内容有改变,就触发 change 事件

    function changeImg() {

        document.getElementById('ifram_form').submit(); // js 语言的提交

        // $("#ifram_form").submit(); // jQuery 方法提交

    }

    ;

    // 当标签内容(包括图片和文字)加载完毕时触发 load 事件


    $("#onload").load(function () {

        var v = $('#onload').contents().find('body').html(); // 返回的数据会在 ifram 中,从ifram中取数据

        var obj = JSON.parse(v); // JavaScript 的反序列化,把字符串转换为数据对象

        alert(obj);

        var tag = document.createElement('img'); // 创建一个 img 标签

        tag.src = "/" + obj.data; // 给标签添加一个属性,并赋值

        $('#prevImg').append(tag); // 在某一个标签的里面,添加一个这个标签的子标签

    });

</script>

后端接收数据的代码

def ajax_upload(request):

    """

    接收前端 Ajax 发送过来的数据和文件

    :param request:

    :return:

    """

    import os,json

    response = BaseReponse()

    try:

        print('reqpost数据>>:', request.POST)

        print('reqfile数据>>:', request.FILES)

        file_obj = request.FILES.get('sub_file_name')

        print('接收到的文件>>:', file_obj)

        print('参数key one 的值>>:', request.POST.get('one'))

        print('参数key two 的值>>:', request.POST.get('two'))


        # file_dir = os.path.join(settings.BASE_DIR, 'img') # 设置接收文件的绝对路径

        # print("文件保存的绝对路径>>:", file_dir)

        """下面的是把接收到的文件保存到服务器上"""

        file_path = os.path.join('static', file_obj.name) # 组合文件的完整路径

        new_file_obj = open(file_path, 'wb')

        [new_file_obj.write(chunk) for chunk in file_obj.chunks()]

        new_file_obj.close()


        """设置一下返回信息和状态"""

        response.status = True

        response.data = file_path

    except Exception as e:

        response.status = False

        response.error = "上传失败"


    return HttpResponse(json.dumps(response.__dict__))

后端得到的数据

reqpost数据>>: <QueryDict: {'one': ['iframe_one'], 'csrfmiddlewaretoken': ['rASMcicdXWgDqO83szbzkVQtY5UOiKpAfYNpNcUfLaml0em0qx3o8hA4spHXZ9r2'], 'two': ['iframe_two']}>

reqfile数据>>: <MultiValueDict: {'sub_file': [<InMemoryUploadedFile: QQ截图20170305224609.png (image/png)>]}>

接收到的文件>>: QQ截图20170305224609.png

参数key one 的值>>: iframe_one

参数key two 的值>>: iframe_two

第三种: 利用 javascript.foram.js 实现 Ajax 提交

简单介绍

实现的功能:可以提交表单和文件

缺点:目前兼容性还不太好,因为 FormDate 这个类是比较新的特性,IE8 及之前版本的浏览器不支持

实现

前端Ajax发送数据的代码:

<h1>利用 Script.form.js 提交文件和表单数据</h1>


<div>

    <form method="post" action="/ajax-upload/" enctype="multipart/form-data">

        上传头像:

        <input type="file" name="sub_file_name" />

        <input type="button" value="提交" />

        <input type="text" name="one" value="FormDataone"/>

        <input type="text" name="two" value="FormDatatwo"/>

    </form>

</div>

    <script>

        // script_form.js

        $("#formjs_btn").on('click', function () {

            var value = $("#sub_file").val()


            if (!value) {

                alert("请先选择文件");

                return false;

            }

            if (!value.match(/.jpg|.jpeg|.gif|.png|.bmp/i)) {

                alert("文件格式错误");

                return false;

            }

            var inp_one = $("input[type='text']").first().val();

            var inp_two = $("input[type='text']").last().val();

            var option = {

                url: '/ajax-upload/',

                type: 'POST',

                dataType: 'json',

                data: {'one': inp_one, 'two': inp_two},

                headers: { // 把认证信息添加到请求的头部,也能实现认证

                    "X-CSRFToken": $.cookie('csrftoken') // 从 cookie 中获取到csrf的值

                }, // 注意这里的 key 必须是这个,这是Django 定义好的

                success: function (data) {

                    alert(JSON.stringify(data)); // js 序列化数据,把数据对象转换为字符

                },

                error: function (data) {

                    alert("--上传失败,请刷新后重试");

                }

            };


            $("#form0").ajaxSubmit(option); // 使用 script.form.js 上传数据和文件

            return false; // 返回false阻止表单再次提交

        });

    </script>

后端接收数据的代码

后端接收数据的代码和第一种或者第二种一样

后端得到的数据

reqpost数据>>: <QueryDict: {'two': ['FormDatatwo', 'FormDatatwo'], 'one': ['FormDataone', 'FormDataone']}>

reqfile数据>>: <MultiValueDict: {'sub_file_name': [<InMemoryUploadedFile: 美女.jpg (image/jpeg)>]}>

接收到的文件>>: 美女.jpg

参数key one 的值>>: FormDataone

参数key two 的值>>: FormDatatwo


相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: