2022-06-07
devops
00
请注意,本文编写于 660 天前,最后修改于 659 天前,其中某些信息可能已经过时。

目录

Bootstrap
安装
布局
栅格系统
col, container
按钮
网站模板
利用登录页面
jquery
安装
文档
元素选择
原生
jquery
属性选择
css操作 css
html操作
加节点
属性操作 attr
子元素选择
内容显示和隐藏
jquery事件函数
点击 事件
原始写法
新写法
jquery的ajax
准备环境
配置静态文件路径
服务端替换html
GET请求
GET跨域请求
复现跨域
解决跨域
POST请求
postman请求 模拟表单
jquery
django csrf 中间件的影响
获取POST请求
跨域
跨域问题
POST json 非上面的简单请求
后端
前端
请求
OPTION 预检请求
POST真正请求
请求分析
后端处理json数据
前端调整发的数据
后端处理数据
练习
分析
前端静态增加
准备模板和路由
后端
前端
实现的效果
前端动态增加
前端添加请求
后端添加路由
后端解决跨域
前端基于数据,动态添加表格
解决跨域分析
JsonP原理
环境
GET 由django提供静态文件的my.js
问题:脚本GET跨域没?
GET 由django路由提供js,application/javascript
本地函数,注入远程对象
前端代码设计函数
后端代码,函数包装对象
前端动态函数
前端设计多个函数,回调某个函数
后端代码,识别函数,函数包装对象
ajax调用jsonp,简化以上代码
重写callback函数名

Bootstrap

老项目, 不会react, vue框架。其他人会使用模板。bootstrap + jquery

布局:

  • h2,p
  • table tr td
  • div + css 绝对,相对,flex, 瀑布

安装

https://getbootstrap.com/docs/4.6/getting-started/introduction/

html
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <title>Hello, world!</title> </head> <body> <h1>Hello, world!</h1> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script> </body> </html>
  1. link css

  2. script, 完成动画

    • jquery 插件

布局

body中所有内容在以下容器中

<div class="container"> </div>

栅格系统

实现boogstrap网页

html
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <title>Hello, world!</title> <style> .container { border: 1px solid red; } .row { border: 1px solid yellowgreen; margin: 5px; } .row div { border: 1px solid blue; margin: 3px; } </style> </head> <body> <h1>Hello, world!</h1> 栅格系统,每行12格 <br> <div class="container"> <div class="row"> <!-- head --> <div class="col-sm"> One of three columns </div> <div class="col-sm"> One of three columns </div> <div class="col-sm"> One of three columns </div> </div> <!-- 侧边栏 页面 页内导航 --> <div class="row"> <div class="col-3"> 1 of 3 </div> <div class="col"> 2 of 3 </div> <div class="col-3"> 3 of 3 </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script> </body> </html>

col, container

https://getbootstrap.com/docs/4.6/layout/overview/#containers

image-20220502174639977

从上到下,适应小分辨率到大分辨率

按钮

将组件放在列中https://getbootstrap.com/docs/4.6/components/alerts/

html
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <title>Hello, world!</title> <style> .container { border: 1px solid red; } .row { border: 1px solid yellowgreen; margin: 5px; } .row div { border: 1px solid blue; margin: 3px; } </style> </head> <body> <h1>Hello, world!</h1> 栅格系统,每行12格 <br> <div class="container"> <div class="row"> <!-- head --> <div class="col-sm"> One of three columns </div> <div class="col-sm"> One of three columns </div> <div class="col-sm"> One of three columns </div> </div> <!-- 侧边栏 页面 页内导航 --> <div class="row"> <div class="col-3"> 1 of 3 </div> <div class="col"> 2 of 3 </div> <div class="col-3"> <button type="button" class="btn btn-primary" onclick="test()">提交</button> <button type="button" class="btn btn-danger">删除</button> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script> <script> function test() { console.log('点击了按钮'); } </script> </body> </html>
  1. 请求html, 请求script, link文件。请求后相当于合并到我们的html文件中。
  2. onclick事件

网站模板

上面有了布局,按钮,怎么使用网站?

example中有大量网站, 下载实例

后台管理页面: https://getbootstrap.com/docs/4.6/examples/dashboard/

登录页面: https://getbootstrap.com/docs/4.6/examples/sign-in/

image-20220502180049636

利用登录页面

下载上面的示例,并找到页面说的名字对应的目录

image-20220502180658591

html
<form class="form-signin"> <img class="mb-4" src="../assets/brand/bootstrap-solid.svg" alt="" width="72" height="72"> <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1> <label for="inputEmail" class="sr-only">Email address</label> <input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus> <label for="inputPassword" class="sr-only">Password</label> <input type="password" id="inputPassword" class="form-control" placeholder="Password" required> <div class="checkbox mb-3"> <label> <input type="checkbox" value="remember-me"> Remember me </label> </div> <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> <p class="mt-5 mb-3 text-muted">&copy; 2017-2021</p> </form>

点了sign in之后,就jquery 发送ajax请求

jquery

ES3 标准, 1999年

2008年,iphone, 国外移动互联网,屏幕自适应

ES5 2009年,还使用jquery

ES6 2015.6 前端框架, 将不再使用jquery, 但是底层使用jquery。

jquery包含以下功能:

  • html元素操作
  • css操作
  • dom操作
  • 事件
  • javascript特效和动画
  • ajax
  • utilities

安装

http://jquery.com/download/ 或CDN

html
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>

生产使用min, 减小流量

文档

https://dsf.jb51.net/201406/books/jquery111(jb51.net).rar

1.11.0版本

重点:发ajax请求, 处理响应

元素选择

原生

操作麻烦

  • innerHTML 里面html
  • innerText 没有标签
html
<!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>Document</title> </head> <body> <!-- #root --> <div id="root"> <span>内容</span> </div> <!-- 原生操作 --> <script> // dom, Document Object Model // window // 浏览器全局对象 // 默认全局对象: window.document document console.log(document.getElementById('root').innerHTML); console.log(document.getElementById('root').innerText); </script> </body> </html>

脚本放在前面的问题, dom树还不存在。放在后面就正常

html
<!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>Document</title> <!-- 原生操作 --> <script> // dom, Document Object Model // window // 浏览器全局对象 // 默认全局对象: window.document document console.log(document.getElementById('root').innerHTML); console.log(document.getElementById('root').innerText); </script> </head> <body> <!-- #root --> <div id="root"> <span>内容</span> </div> </body> </html>

加载事件, 手工在body放一个事件,前面写函数就正常了。jquery引入就正常。

html
<!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>Document</title> <!-- 原生操作 --> <script> function test() { // dom, Document Object Model // window // 浏览器全局对象 // 默认全局对象: window.document document console.log(document.getElementById('root').innerHTML); console.log(document.getElementById('root').innerText); } </script> </head> <body onload="test()"> <!-- #root --> <div id="root"> <span>内容</span> </div> </body> </html>

jquery

解决页面元素加载

选择器标签
$("p")<p>
$('p.intro')<p class="intro">
$('p#demo')<p id="demo">
html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { // 这个就是页面加载完成的回调 console.log(document.getElementById('root')); // 原生对象 console.log(document.getElementById('root').innerHTML); // 原生对象 console.log($(document.getElementById('root')).html()); // 将原生对象包装为jquery对象 console.log($('#root')); // 提供了 init对象, 提供了统一扩音器 console.log('-'.repeat(13)); console.log($('div')); // 选择div元素 console.log($('<div>xyz</div>')); // 包装div标签, 新建div标签,不在dom树中 }) </script> </head> <body> <!-- #root --> <div id="root"> <span>内容</span> </div> </body> </html>

属性选择

jquery使用xpath表达式选择带属性的元素

选择器描述
$('[href]')有href属性的所有标签
$('[href="#"]')href="#"的所有标签
$('[href!="#"]')href!="#"的所有标签
([href('[href=".jpg"]')href以.jpg结尾的所有标签

css操作 css

名称描述
$('').css('key')获取css
$('').css('key', 'value')赋值css
$('').css({'key':'value','key', 'value','key', 'value'})赋值多个css

image-20220505090730131

html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { const root = $('root') // 内容变红色 $('#root .content').css('color', 'red') // .content 前景蓝,背景灰,20px大小 $('.content').css({ 'color': 'blue', 'font-size': '20px', 'background-color': '#f0f0f0' }) const s = $('.content') // 读取 console.log(s.css('color')); // rgb(0, 0, 255) 蓝色 // 赋值 s.css('margin', '20px') }) </script> </head> <body> <!-- #root --> <div id="root"> <span class="content">内容</span> <span>123</span> </div> </body> </html>

html操作

html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { const l = $('span:last-child') // 取标签和内容 有标签 console.log(l.html()); // 123 // 取内容 无标签 console.log(l.text()); // 修改内容 l.html('123411') l.html('<a href="#">' + l.html() + '</a>') }) </script> </head> <body> <!-- #root --> <div id="root"> <span class="content">内容</span> <span> <p>123</p> </span> </div> </body> </html>

加节点

image-20220505091334088

html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { const root = $('#root') // 子元素 头加一个元素 root.prepend('<div>root 子 header</div><hr/>') // 子元素 尾加一个元素 root.append('<hr/><div>root 子 footer</div>') // 添加兄弟 root.after('<div>root 兄弟 after</div>') root.after($('<div>jquery标签</div>')) // 内容需要变化 const temp = $('<div/>') root.append(temp) temp.html('footer+++++++') temp.html( temp.html() + 'footer ++++2 ' ) // 添加列表 temp.html(` <ul> <li>1</li> <li>2</li> <li>3</li> </ul> `) root.after(` <ul> <li>a</li> <li>b</li> <li>c</li> </ul> `) }) </script> </head> <body> <!-- #root --> <div id="root"> <span class="content">内容</span> <span>123</span> </span> </div> </body> </html>

属性操作 attr

image-20220505093620549

名称描述
$('').attr('key')获取attr
$('').attr('key', 'value')赋值attr
$('').attr({'key':'value','key', 'value','key', 'value'})赋值多个attr
html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { // 属性操作 const content = $('.content') content.append('<img alt="logo" >') // 添加图片 $('.content img').attr('src', 'http://myapp.image.qiniu.mykernel.cn/favicon.png') // 获取图片属性 console.log($('.content img').attr('src')); // 多个属性 $('.content img').attr({ 'src': 'http://myapp.image.qiniu.mykernel.cn/favicon.png', 'alt': 'logo', 'width': '100px', // 图片一般修改宽度 }) // click点击事件,再修改也可以 }) </script> </head> <body> <!-- #root --> <div id="root"> <span class="content">内容</span> <span>123</span> </span> </div> </body> </html>

子元素选择

html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { // first 第1个 $('ul li:first').css('color', 'red') // 奇数变色 odd; 索引0 1 2 3 $('ul li:odd').css('background-color', '#f0f0f0') // 无论匹配多少个, 首个变色 $('ul li:first').css('color', 'green') // 父元素匹配多个, 每个父的首个子元素匹配。跨元素匹配首个 $('ul li:first-child').css('background-color', 'black') // 第几个, 不按索引,接自然数从1开始 $('ul li:nth-child(2)').css('color', 'red') // 匹配ul父元素中的子元素,有混合类型时,只匹配ul类型的首个元素; 不混合也匹配 $('ul:first-of-type').css({ 'border': '1px solid green', }) // 匹配ul父元素中的子元素,只有单一类型时, 只匹配ul类型的首个元素 $('ul:first-child').css({ 'border': '1px solid blue', }) }) </script> </head> <body> <!-- #root --> <div id="root"> <span class="content">内容</span> <span>123</span> </span> <ul> <li>a</li> <li>b</li> <li>c</li> </ul> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> </div> <div> <ul> <li>e</li> <li>f</li> <li>g</li> </ul> <ul> <li>4</li> <li>5</li> <li>6</li> </ul> </div> </body> </html>

内容显示和隐藏

html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { // 隐藏123 console.log( $('span:nth-of-type(2)')); // 隐藏 $('span:nth-of-type(2)').css('display','none') // 显示 $('span:nth-of-type(2)').css('display', '') // 转换块 $('span:nth-of-type(2)').css('display', 'block') // $('#root').css('display', 'none') // $('#root').css('height', '100px') // $('#root').css('width', '100px') }) </script> </head> <body> <!-- #root --> <div id="root"> <span class="content">内容</span> <span>123</span> </span> </div> </body> </html>

jquery事件函数

点击 事件

原始写法

html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { }) // 原始写法 function test() { console.log('点击 了test'); } </script> </head> <body> <!-- #root --> <div id="root"> <span class="content" onclick="test()">请点击我</span> <span>123</span> </span> </div> </body> </html>

新写法

html
<!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>Document</title> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <!-- 原生操作 --> <script> // $(document).ready(function() { // // $(document) 相当于选择器,结果变成jquery对象 // // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。 // console.log('页面加载完成'); // }); // 简化版 $(function() { let count = 1 $('.content').click(function(event) { console.log(event,'~'.repeat(12)); // event.target事件中包含了你产生此事件(click)的对象 <span class="content">请点击我</span> console.log(event.target); // 每点一次,在控制台中输出信息 let e = $('<div>' + count++ + '</div>') e.css({ 'margin-bottom': '5px', 'border': '1px solid #ccc', }) $('.console').append(e) }) }) </script> </head> <body> <!-- #root --> <div id="root"> <span class="content" >请点击我</span> <span>123</span> </span> </div> <div class="console"> </div> </body> </html>

优化,每次添加css, 每个添加的元素加一个类,style中统一定css

diff
// 每点一次,在控制台中输出信息 + let e = $('<div class="card">' + count++ + '</div>') $('.console').append(e) }) }) </script> + <style> .card { margin-bottom: 5px; border: 1px solid #ccc; } </style>

jquery的ajax

image-20220505103111849

jQuery对XMLHttpRequest组件的调用接口实现了封闭,更加方便调用。默认异步请求

解决的问题:同步请求,每一个点击,整个页面需要刷新。注册时, 如果用户提交时,页面提交时页面卡住, 服务端发现用户名冲突,需要用户再次请求注册,用户会重新刷新,刷新后用户提交的信息会丢失,体验差。2005之后,ajax出现异步ajax请求,异步获取xml, 后来使用json, 比xml更有效的承载数据。而名字保留下来。Ajax技术

准备环境

salary/urls.py

python
"""salary URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.2/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path, include from django.http import HttpResponse from django.shortcuts import render def index(request: HttpResponse): return render(request, template_name='index.html', context={"test": 'how are you?'}) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('', index) ]

templates/index.html

html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> </head> <body> {{ test }} </body> </html>

image-20220505112629285

配置静态文件路径

  • 主目录 STATICFILES_DIRS = [BASE_DIR / 'testst'] 定义
  • app目录下的 static目录

salary/urls.py

python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpResponse): print('*'*30) print(*filter(lambda x:x[0].startswith('STATIC'),settings.__dict__.items()),sep='\n') # ('STATIC_URL', '/static/') # ('STATICFILES_FINDERS', # ['django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder']) # ('STATICFILES_DIRS', []) # FileSystemFinder中, 找到返回,没有找到继续找,找完就 继续通过 AppDirectoriesFinder在注册的app中static子目录查找 。 print('*'*30) return render(request, template_name='index.html', context={"test": 'how are you?'}) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('', index) ]

salary/settings.py

python
# Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [BASE_DIR / 'testst']

准备jquery下载文件

powershell
invoke-webrequest https://code.jquery.com/jquery-3.6.0.min.js -outfile D:\py_projects\djangoT39\testst\js\jquery-3.6.0.min.js

templates/index.html

html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="/static/js/jquery-3.6.0.min.js"></script> </head> <body> {{ test }} </body> </html>

访问http://127.0.0.1:8000/static/js/jquery-3.6.0.min.js

正常

服务端替换html

不手工写死路径 /static/js/jquery-3.6.0.min.js 只写static 加逻辑路径

html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} </body> </html>

GET请求

templates/index.html

html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <button class="ajaxget"> Ajax Get </button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget?a=1&b=2&b=3", function (data) { console.log(data, '~'.repeat(50)); }); }) }) </script> </body> </html>
  1. 一个按钮
  2. jquery添加点击事件,事件中发起ajax请求。参考文档 jquery 1.11, $.get(路径, 成功回调), 失败就异常。

salary/urls.py

python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test_get(request: HttpRequest): print('*'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print() print('*'*30) return JsonResponse({'books': [ (1,'python', 20), (2,'go', 5), ]}) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('testget', test_get), # 按钮get ]
  1. 当用户请求 localhost/index 就是主页,主页只需要模板。
  2. 模板中的按钮 ajax 请求/testget, 返回json数据

用户点按钮之后

image-20220505165043169

pycharm中返回

python
****************************** GET text/plain <QueryDict: {'a': ['1'], 'b': ['2', '3']}> ****************************** [05/May/2022 16:44:26] "GET /testget?a=1&b=2&b=3 HTTP/1.1" 200 44
  1. 请求是text/plain请求
  2. 注意b有多个值,所以查询参数是一个多值字典

在ajax中,查询 参数也可以使用以下方式传递,但是后端返回

js
$.get("/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); });
python
GET text/plain <QueryDict: {'a': ['1'], 'b': ['3']}>

当使用map传递时,相同key的值就只会有1个

GET跨域请求

复现跨域

当替换上面的get请求的路径为 http://localhost/testget

templates/index.html

html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <button class="ajaxget"> Ajax Get </button> <button class="ajaxgetcors"> Ajax Get 跨域请求 </button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxgetcors').click(function (event) { console.log(event.target, '~'.repeat(30)); $.get("http://localhost:8000/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) }) </script> </body> </html>

返回结果

image-20220505170557384

  1. 状态 CORS ERROR 表示跨域资源访问问题

而后端响应是200, 说明浏览器拿到数据,但是数据扔了

python
****************************** GET text/plain <QueryDict: {'a': ['1'], 'b': ['3']}> ****************************** [05/May/2022 17:07:20] "GET /testget?a=1&b=3 HTTP/1.1" 200 44

解决跨域

后端代码salary/urls.py

diff
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test_get(request: HttpRequest): print('*'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print() print('*'*30) res = JsonResponse({'books': [ (1,'python', 20), (2,'go', 5), ]}) + res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' + return res # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('testget', test_get), # 按钮get ]

这个上面是仅允许http://127.0.0.1:8000 域。如果想任何源站访问时,均允许, 将值修改为'*'

POST请求

postman请求 模拟表单

image-20220505172831323

jquery

django csrf 中间件的影响

templates/index.html

<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <button class="ajaxget"> Ajax Get </button> <button class="ajaxgetcors"> Ajax Get 跨域请求 </button> <button class="ajaxpost"> Ajax POST 请求 </button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxgetcors').click(function (event) { console.log(event.target, '~'.repeat(30)); $.get("http://localhost:8000/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpost').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testget post用请求报文的body上传数据,不需要查询参数 $.post("/testpost", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) }) </script> </body> </html>

salary/urls.py

"""salary URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.2/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) # GET POST 所有method请求 def test_get(request: HttpRequest): print('*'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print() print('*'*30) res = JsonResponse({'books': [ (1,'python', 20), (2,'go', 5), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res def test_post(request: HttpRequest): print('+'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print(request.POST) # 查询字符串, 多值字典 print() print('+'*30) res = JsonResponse({'books': [ (1,'python', 20), ]}) # res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('testget', test_get), # 按钮get path('testpost', test_post), # 按钮get ]
  1. request.GET 请求头的首行。
  2. request.POST 请求的body中。

image-20220505173052907

请求时响应

python
Forbidden (CSRF cookie not set.): /testget Forbidden (CSRF cookie not set.): /testget [05/May/2022 17:20:25] "POST /testget HTTP/1.1" 403 2801

取消此中间件 salary/settings.py

MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]

获取POST请求

++++++++++++++++++++++++++++++ POST application/x-www-form-urlencoded <QueryDict: {}> <QueryDict: {'a': ['1'], 'b': ['3']}> ++++++++++++++++++++++++++++++
  1. ajax的post请求,是表单提交 application/x-www-form-urlencoded
  2. 首行没有查询参数
  3. body有form data 有

跨域

templates/index.html

<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <button class="ajaxget"> Ajax Get </button> <button class="ajaxgetcors"> Ajax Get 跨域请求 </button> <button class="ajaxpost"> Ajax POST 请求 </button> <button class="ajaxpostcors"> Ajax POST 跨域请求 </button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxgetcors').click(function (event) { console.log(event.target, '~'.repeat(30)); $.get("http://localhost:8000/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpost').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("/testpost", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpostcors').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("http://localhost:8000/testpost?k1=v1&k2=v2", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) }) </script> </body> </html>

同样会报错,以下解决

salary/urls.py

diff
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) # GET POST 所有method请求 def test_get(request: HttpRequest): print('*'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print() print('*'*30) res = JsonResponse({'books': [ (1,'python', 20), (2,'go', 5), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res def test_post(request: HttpRequest): print('+'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, URL 中 print(request.POST) # 查询字符串, 多值字典. 请求报文的body print() print('+'*30) res = JsonResponse({'books': [ (1,'python', 20), ]}) + res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('testget', test_get), # 按钮get path('testpost', test_post), # 按钮get ]

跨域问题

每个接口均需要配置跨域的首部

POST json 非上面的简单请求

后端

salary/urls.py

python
"""salary URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.2/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) # GET POST 所有method请求 def test_get(request: HttpRequest): print('*'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print() print('*'*30) res = JsonResponse({'books': [ (1,'python', 20), (2,'go', 5), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res def test_post(request: HttpRequest): print('+'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, URL 中 print(request.POST) # 查询字符串, 多值字典. 此方法对应 application/x-www-form-urlencoded 和 multipart/form-data 传统表单方法 print() print('+'*30) res = JsonResponse({'books': [ (1,'python', 20), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res def test_json(request: HttpRequest): """ json请求时,跨域时,会出现预检请求 OPTIONS text/plain <QueryDict: {'k': ['5'], 'v': ['6']}> <QueryDict: {}> False b'' """ print('+'*30) print(request.method) # application/json print(request.content_type) print(request.GET) # 查询字符串, URL 中 print(request.POST) # 虽然post请求,但是我们发的内容类型是application/json; 此方法对应 application/x-www-form-urlencoded 和 multipart/form-data 传统表单方法 print(request.is_ajax()) # True print(request.body) # json从这里提取,没有flask的json属性 print('+'*30) res = JsonResponse({'books': [ (1,'c++', 20000), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' res.headers['Access-Control-Allow-Headers'] = 'content-type' return res # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('testget', test_get), # 按钮get path('testpost', test_post), # 按钮get path('testjson', test_json), # 按钮post ]

前端

templates/index.html

html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <h1>简单请求</h1> <button class="ajaxget"> Ajax Get </button> <button class="ajaxgetcors"> Ajax Get 跨域请求 </button> <button class="ajaxpost"> Ajax POST 请求 </button> <button class="ajaxpostcors"> Ajax POST 跨域请求 </button> <h1>json 预检请求</h1> <button class="ajaxjson">Ajax POST json 同域请求, 同域不出现预检</button> <button class="ajaxjsoncors">Ajax POST json 跨域请求</button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxgetcors').click(function (event) { console.log(event.target, '~'.repeat(30)); $.get("http://localhost:8000/testget", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpost').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("/testpost", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpostcors').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("http://localhost:8000/testpost?k1=v1&k2=v2", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) // 同域不出现预检 $('.ajaxjson').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数 // 简单格式, 只支持 application/x-www-form-urlencoded // $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) { // console.log(data, '~'.repeat(50)); // }); // 原生格式使用请求体的内容类型 application/json $.ajax({ type: "POST", url: "/testjson?k=5&v=6", contentType: "application/json", data: { a: 1, b: 2, b: 3 }, success: function (msg) { console.log(msg, '+'.repeat(50)); }, // 成功回调 }); }) $('.ajaxjsoncors').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数 // 简单格式, 只支持 application/x-www-form-urlencoded // $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) { // console.log(data, '~'.repeat(50)); // }); // 原生格式使用请求体的内容类型 application/json $.ajax({ type: "POST", url: "http://localhost:8000/testjson?k=5&v=6", contentType: "application/json", // MIME 类型 data: { a: 1, b: 2, b: 3 }, success: function (msg) { console.log(msg, '+'.repeat(50)); }, // 成功回调 }); }) }) </script> </body> </html>

请求

OPTION 预检请求

image-20220506091344761

POST真正请求

image-20220506091420954

请求分析

当点击 Ajax POST json 跨域请求, 会出现2个请求, 第1是预检请求。会拿着和用户请求的URL+查询字符串,和Access-Control-Request-* 请求服务器

python
++++++++++++++++++++++++++++++ OPTIONS text/plain <QueryDict: {'k': ['5'], 'v': ['6']}> <QueryDict: {}> False b'' ++++++++++++++++++++++++++++++ [06/May/2022 09:13:03] "OPTIONS /testjson?k=5&v=6 HTTP/1.1" 200 30

服务器收到的请求方法是 OPTIONS, 请求的类型是 text/plain , 查询 字符存在,不是ajax请求,表单请求体为空,此请求需要响应OK,才可以进行后续的请求

python
++++++++++++++++++++++++++++++ POST application/json <QueryDict: {'k': ['5'], 'v': ['6']}> <QueryDict: {}> False b'a=1&b=3' ++++++++++++++++++++++++++++++ [06/May/2022 09:13:03] "POST /testjson?k=5&v=6 HTTP/1.1" 200 30

服务器收到POST, 请求体的类型是 application/json ,查询字符,表单请求体为空, 不是ajax请求, 请求体存在

后端处理json数据

print(request.body) b'a=1&b=3' 这个给表单方法处理

这个问题是发数据的问题

前端调整发的数据

diff
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <h1>简单请求</h1> <button class="ajaxget"> Ajax Get </button> <button class="ajaxgetcors"> Ajax Get 跨域请求 </button> <button class="ajaxpost"> Ajax POST 请求 </button> <button class="ajaxpostcors"> Ajax POST 跨域请求 </button> <h1>json 预检请求</h1> <button class="ajaxjson">Ajax POST json 同域请求, 同域不出现预检</button> <button class="ajaxjsoncors">Ajax POST json 跨域请求</button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxgetcors').click(function (event) { console.log(event.target, '~'.repeat(30)); $.get("http://localhost:8000/testget", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpost').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("/testpost", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpostcors').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("http://localhost:8000/testpost?k1=v1&k2=v2", { a: 1, b: 2, b: 3 }, function (data) { console.log(data, '~'.repeat(50)); }); }) // 同域不出现预检 $('.ajaxjson').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数 // 简单格式, 只支持 application/x-www-form-urlencoded // $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) { // console.log(data, '~'.repeat(50)); // }); // 原生格式使用请求体的内容类型 application/json $.ajax({ type: "POST", url: "/testjson?k=5&v=6", contentType: "application/json", + data: JSON.stringify({ a: 1, b: 2, b: 3 }), // javascript内建对象JSON success: function (msg) { console.log(msg, '+'.repeat(50)); }, // 成功回调 }); }) $('.ajaxjsoncors').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数 // 简单格式, 只支持 application/x-www-form-urlencoded // $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) { // console.log(data, '~'.repeat(50)); // }); // 原生格式使用请求体的内容类型 application/json $.ajax({ type: "POST", url: "http://localhost:8000/testjson?k=5&v=6", contentType: "application/json", // MIME 类型 + data: JSON.stringify({ a: 1, b: 2, b: 3 }), // javascript内建对象JSON success: function (msg) { console.log(msg, '+'.repeat(50)); }, // 成功回调 }); }) }) </script> </body> </html>

后端处理数据

现在python拿到的数据

python
++++++++++++++++++++++++++++++ POST application/json <QueryDict: {'k': ['5'], 'v': ['6']}> <QueryDict: {}> False b'{"a":1,"b":3}' ++++++++++++++++++++++++++++++

现在可以处理了, option方法请求时,请求体是空的,post方法才有值,才可以转成字典

diff
"""salary URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.2/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) # GET POST 所有method请求 def test_get(request: HttpRequest): print('*' * 30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print() print('*' * 30) res = JsonResponse({'books': [ (1, 'python', 20), (2, 'go', 5), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res def test_post(request: HttpRequest): print('+' * 30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, URL 中 print(request.POST) # 查询字符串, 多值字典. 请求报文的body print() print('+' * 30) res = JsonResponse({'books': [ (1, 'python', 20), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res def test_json(request: HttpRequest): """ json请求时,跨域时,会出现预检请求 OPTIONS text/plain <QueryDict: {'k': ['5'], 'v': ['6']}> <QueryDict: {}> False b'' 真正请求,返回 b'a=1&b=3' 返回bytes """ print('+' * 30) print(request.method) print(request.content_type) # application/json print(request.GET) # 查询字符串, URL 中 print( request.POST) # 但是post请求,但是我们发的内容类型是application/json; 此方法对应 application/x-www-form-urlencoded 和 application/form-data 传统表单方法 print(request.is_ajax()) # True print(request.body) # json从这里提取,没有flask的json属性; b'a=1&b=3' 这个给表单方法处理 + if request.method == "POST": + import json + print(json.loads(request.body), '&0' * 30) # {'a': 1, 'b': 3} print('+' * 30) res = JsonResponse({'books': [ (1, 'c++', 20000), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' res.headers['Access-Control-Allow-Headers'] = 'content-type' return res # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('testget', test_get), # 按钮get path('testpost', test_post), # 按钮get path('testjson', test_json), # 按钮get ]

练习

Ajax方法,提交GET。从服务器返回数据,使用表格显示,要求使用JS对表格动态追加。

分析

  1. 实现前端的静态增加
  2. 实现请求数据,增加

前端静态增加

准备模板和路由

后端

salary/urls.py

python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 ]
前端

templates/test.html

<!DOCTYPE html> {% load static %} <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>Document</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <style> .console { padding-top: 22px; } table, tr, td,th { border-collapse: collapse; border: 1px solid black; } </style> </head> <body> <h1>{{ name|add:".cn" }}</h1> <button>GET动态添加表格</button> <div class="console"> <table> <tr> <th>序号</th> <th>书名</th> <th>数量</th> </tr> </table> </div> <script> $(function() { $('button').click(function() { console.log('click'); $('.console table').append(` <tr> <td>1</td> <td>2</td> <td>3</td> </tr> `) }) }) </script> </body> </html>
实现的效果

点击按钮,动态添加表格

image-20220506101848905

前端动态增加

前端添加请求

templates/test.html

<!DOCTYPE html> {% load static %} <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>Document</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <style> .console { padding-top: 22px; } table, tr, td, th { border-collapse: collapse; border: 1px solid black; } </style> </head> <body> <h1>{{ name|add:".cn" }}</h1> <button>GET动态添加表格</button> <div class="console"> <table> <tr> <th>序号</th> <th>书名</th> <th>数量</th> </tr> </table> </div> <script> $(function () { $('button').click(function () { $.ajax({ type: "POST", url: "http://localhost:8000/testjson", contentType: "application/json", data: JSON.stringify({a:1,b:2,c:3}), success: function (msg) { console.log(msg,'+'.repeat(30)); } }); $('.console table').append(` <tr> <td>1</td> <td>2</td> <td>3</td> </tr> `) }) }) </script> </body> </html>

image-20220506102253362

后端添加路由

salary/urls.py

from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) def test_json(request:HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 ]
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) def test_json(request:HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 ]
python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) def test_json(request:HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) return JsonResponse({ 'books': [ (1,'c',10), (2,'c++',11), (3,'python',200), (4,'go',2), ] }) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 ]

image-20220506102618103

现在预检不正常,是CORS 错误了,所以需要跨域首部就是 预检的 Access-Control-Request-* 这些添加到后端

Access-Control-Request-Headers: content-type Access-Control-Request-Method: POST

控制台有配置方法 Access-Control-Allow-Origin 和orgin后面的地址添加到后端

test:1 Access to XMLHttpRequest at 'http://localhost:8000/testjson' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. jquery-3.6.0.min.js:2 POST http://localhost:8000/testjson net::ERR_FAILED

添加 Access-Control-Allow-Headers 和 Request header field content-type

Access to XMLHttpRequest at 'http://localhost:8000/testjson' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response. jquery-3.6.0.min.js:2 POST http://localhost:8000/testjson net::ERR_FAILED

后端解决跨域

salary/urls.py

python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) def test_json(request:HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) res = JsonResponse({ 'books': [ (1,'c',10), (2,'c++',11), (3,'python',200), (4,'go',2), ] }) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE' return res # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 ]

image-20220506103135333

前端基于数据,动态添加表格

templates/test.html

html
<!DOCTYPE html> {% load static %} <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>Document</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <style> .console { padding-top: 22px; } table, tr, td, th { border-collapse: collapse; border: 1px solid black; } </style> </head> <body> <h1>{{ name|add:".cn" }}</h1> <button>GET动态添加表格</button> <div class="console"> <table> <tr> <th>序号</th> <th>书名</th> <th>数量</th> </tr> </table> </div> <script> $(function () { $('button').click(function () { $.ajax({ type: "POST", url: "http://localhost:8000/testjson", contentType: "application/json", data: JSON.stringify({ a: 1, b: 2, c: 3 }), success: function (msg) { console.log(msg, '+'.repeat(30)); let books = msg.books for (let book of books) { // console.log(book); let [id, book_name, nums] = book $('.console table').append(` <tr> <td>${id}</td> <td>${book_name}</td> <td>${nums}</td> </tr> `) } } }); }) }) </script> </body> </html>

解决跨域分析

上面的跨域,是网站写的代码决定的,跟用户没有关系。如果你写的后台,后台需要解决这个问题。

解决跨域的方法

  1. nginx代理到后端,就解决。
  2. 后台添加跨域。

如果第3方人家请求你,你允许他,你就需要解决跨域问题。如果你访问第3方后台接口(阿里, 腾讯),他需要解决,他不一定需要修改代码,可以使用jsonp。

jsonp调用第3方接口常用方式

JsonP原理

<img> <link> <script> 等标签, GET方法可以使用不同域的文件

例如:获取天气网站数据,GET请求数据;一般是jsonp接口。协议要点,允许 用户传递callback参数给服务端,服务端将数据传递给callback函数,之后你在本地的此函数中提供数据即可。

环境

devops\index.html

<!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>Document</title> <script src="static/js/my.js"></script> </head> <body> <script> console.log(x); </script> </body> </html>

devops\static\js\my.js

const x = 'abc1x'

visual code 的 live server 插件 浏览index.html

可以看到打印的值

GET 由django提供静态文件的my.js

http://127.0.0.1:8000/static/js/my.js

image-20220506130921584

修改 devops\index.html

diff
<!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>Document</title> + <script src="http://127.0.0.1:8000/static/js/my.js"></script> </head> <body> <script> console.log(x); </script> </body> </html>

image-20220506131214595

问题:脚本GET跨域没?

一般我们项目开发,静态文件,使用CDN路径。以下3个标签均是GET请求, 可以跨域

html
link script img <!-- 防盗链 -->

服务端不需要做任何改动, 客户端正常访问

image-20220506131849382

GET 由django路由提供js,application/javascript

salary/urls.py

python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) def test_json(request:HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) res = JsonResponse({ 'books': [ (1,'c',10), (2,'c++',11), (3,'python',200), (4,'go',2), ] }) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE' return res def test_script(request:HttpRequest): return HttpResponse("const x = 'fffhelo'",content_type='application/javascript') # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 path('testscript', test_script), # GET ]

注意,返回MIME类型为 application/javascript

devops\index.html

<!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>Document</title> <script src="http://127.0.0.1:8000/testscript"></script> </head> <body> <script> console.log(x); </script> </body> </html>

image-20220506132151914

本地函数,注入远程对象

前端代码设计函数

devops\index.html

<!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>Document</title> </head> <body> <script> function t123(data) { console.log(data, '^'.repeat(5)); } </script> <script src="http://127.0.0.1:8000/testscript"></script> </body> </html>
后端代码,函数包装对象

salary/urls.py

python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request: HttpRequest): return render(request, template_name='test.html', context={'name': 'mykernel'}) def test_json(request: HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) res = JsonResponse({ 'books': [ (1, 'c', 10), (2, 'c++', 11), (3, 'python', 200), (4, 'go', 2), ] }) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE' return res def test_script(request: HttpRequest): text = """ t123({a:100, b: 'abcd'}) """ return HttpResponse(text, content_type='application/javascript') # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 path('testscript', test_script), # GET ]

注意:这里t123({a:100, b: 'abcd'})就是远程的对象

script标签可以跨域发GET请求

python
import json def test_script(request: HttpRequest): text = """t123({})""".format(json.dumps({'a':111100, 'b': 'abcd'})) # 查了数据库 return HttpResponse(text, content_type='application/javascript')

image-20220506134449671

前端动态函数

前端设计多个函数,回调某个函数

devops\index.html

html
<!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>Document</title> </head> <body> <script> function t234(data) { console.log(data, '^'.repeat(5)); } </script> <script src="http://127.0.0.1:8000/testscript?callback=t234"></script> </body> </html>
后端代码,识别函数,函数包装对象

salary/urls.py

python
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request: HttpRequest): return render(request, template_name='test.html', context={'name': 'mykernel'}) def test_json(request: HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) res = JsonResponse({ 'books': [ (1, 'c', 10), (2, 'c++', 11), (3, 'python', 200), (4, 'go', 2), ] }) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE' return res import json def test_script(request: HttpRequest): fn = request.GET.get('callback','ttt') # 前端使用哪个函数 text = """{}({})""".format(fn,json.dumps({'a':111100, 'b': 'xxxabcd'})) # 查了数据库 return HttpResponse(text, content_type='application/javascript') # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 path('testscript', test_script), # GET ]

ajax调用jsonp,简化以上代码

devops\index.html

html
<!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>Document</title> <script src="static/js/jquery-3.6.0.min.js"></script> </head> <body> <!-- <script> function t234(data) { console.log(data, '^'.repeat(5)); // 相当于ajax成功时回调 } </script> --> <!-- <script src="http://127.0.0.1:8000/testscript?callback=t234"></script> --> <!-- 相当于下面, 成功时回调 --> <script> $(function () { $.ajax({ type: "GET", url: "http://127.0.0.1:8000/testscript", dataType: "jsonp", success: function(msg) { console.log(msg,'+'.repeat(12)); } }); }) </script> </body> </html>

ajax的jsonp请求时,不需要添加callback查询参数, 在真正请求时,会自动添加一个随机函数(由ajax内部使用一个函数),如下图:

image-20220506141143880

服务端就响应了随机函数加一堆对象

image-20220506141323349

重写callback函数名

这里cb函数名, 和jsonp的随机函数名由你调用的文档中决定

diff
<!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>Document</title> <script src="static/js/jquery-3.6.0.min.js"></script> </head> <body> <!-- <script> function t234(data) { console.log(data, '^'.repeat(5)); // 相当于ajax成功时回调 } </script> --> <!-- <script src="http://127.0.0.1:8000/testscript?callback=t234"></script> --> <!-- 相当于下面, 成功时回调 --> <script> $(function () { $.ajax({ type: "GET", url: "http://127.0.0.1:8000/testscript", dataType: "jsonp", + jsonp: 'cb', + jsonpCallback: 'fn', success: function(msg) { console.log(msg,'+'.repeat(12)); } }); }) </script> </body> </html>

本文作者:mykernel

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!