博客列表 >json、ajax和跨域请求jsonp细说

json、ajax和跨域请求jsonp细说

G
G原创
2020年11月06日 17:40:461171浏览

json

  • 什么是json:json 是 js 的对象表示法,是通用的跨编程语言的轻量级数据交换/传输/存储格式
    • jsonjs的区别
      1. json 不是值,不能赋值给变量,没有变量
      2. json 不是 js 语句,没有分号
      3. json 中的属性必须加双引号, 哪怕是合法属性名
  1. // JS对象:
  2. const user = {
  3. name:"GGG",
  4. email = "12345679@youyou6.net",
  5. age = 20,
  6. };
  1. // JS对象表示法:json数据:
  2. {
  3. "name" = "GGG",
  4. "email" = "123456798@youyou6.net,
  5. "age" = 20 //最后一项不能有逗号(json不能写注释,这里是为了说明)
  6. } // 结束不能有分号;
  1. - `json`的数据类型:
  2. 1. 数值
  3. 2. 布尔值
  4. 3. 字符串
  5. 4. null
  6. 没有underfined
  7. 5. 复合类型:对象和数组

json 只支持字面量

  1. let user = `{
  2. "name": "GGG",
  3. "email": "123456@youyou6.net",
  4. "age": "20"
  5. }`;

PS:

  1. json 不能有注释
  2. js 字符串需要解析为 js 对象才可以用个到浏览器之中。

JSON.parse(jsonStr)

通过 JSON.parse()可以将一个 json 字符串数据转换为一个 JS 对象,方便调用和数据的处理。

  1. // 设置一个json字符串(字面量字符串)
  2. let user = `{
  3. "name": "GGG",
  4. "email": "123456@youyou6.net",
  5. "age": "20"
  6. }`;
  7. let num = `{
  8. "id" : 1,
  9. "price" : 55,
  10. "num" : "暂无存货"
  11. }`;

语法:变量 = JSON.parse(json字符串) =>将 json 模板字面量转化为一个对象object

  1. // 通过JSON.parse接口将json字符串转换为js对象,方便数据调用和处理
  2. const obj = JSON.parse(user);
  3. console.log(obj);
  4. const pac = JSON.parse(num);
  5. console.log(pac);
  6. console.log(typeof pac);


JSON.stringify

作用:将 JS 对象/数组/属性/值等转换为 Json 字符串,方便 json 存储和使用。
变量 = JSON.stringify(对象/值/数组等)
工作方法:

演示:

  1. const produce = {
  2. name: "手机",
  3. price: 88888,
  4. num: 99999,
  5. };
  6. const poduc = JSON.stringify(produce);
  7. console.log(poduc);

Ajax

同步与异步

以前端请求,后端响应为例

  • 同步: 前端发请求, 必须等到后端响应完成,才允许发送另一个请求
  • 异步: 前端发请求后不等待后端响应结果继续执行,后端响应完成通过事件通知前端处理

    异步最常用的处理形式就是回调函数

XLMHttpRequest 对象

XMLHttpRequest是浏览器提供的,处理异步请求的宿主对象,而非 JS 内置对象
用于创建请求对象之中。
const obj = new XMLHttpRequest

GETPOST请求

  • GET请求
    GET请求的创建和完成方式分为以下几步:
    • 服务器: 返回 JSON
    • 前端: JSON.parse()解析 JSON 字符串

  1. 创建请求对象:new XMLHttpRequest
  2. 监听请求回调:onreadystatechange

    onreadystatechange:监听变量名.readystate变化 0,1,2,3,4表示成功。状态为 4 时表示请求回调成功

  3. 初始化请求参数:open

    语法:open(请求类型,请求地址,是否异步)
    演示:变量名.open("GET","http://youyou6.net/open.php",true)

  4. 发送请求:send()

    通常为send() 括号内的参数不写,但是为了避免其他浏览器识别出错,或出现其他 BUG,建议参数为null
    最终语法:send(null)

  5. 设置回调函数的方法来处理数据
  1. <title>Ajax-GET</title>
  2. <style>
  3. form {
  4. display: inline-grid;
  5. grid-template-columns: 5em 15em;
  6. gap: 1em;
  7. padding: 1em;
  8. border: 1px solid #000;
  9. background-color: lightcyan;
  10. }
  11. form button {
  12. grid-area: auto / 2 / auto / span 1;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <form action="" onsubmit="return false;">
  18. <label for="username">用户名:</label>
  19. <input type="text" id="username" name="username" />
  20. <label for="email">邮箱:</label>
  21. <input type="email" id="email" name="email" />
  22. <button>保存</button>
  23. </form>
  24. <script>
  25. // 1.创建请求对象
  26. const url = new XMLHttpRequest();
  27. // 2.监听监控回调
  28. // 通过事件监听器监听变化,传值给show函数,采用冒泡方式
  29. url.addEventListener("readystatechange", show, false);
  30. // 3.初始化请求参数
  31. url.open("GET", "http://demo.io/test1.php", true);
  32. // 4.发送请求
  33. url.send(null);
  34. // 设置回调函数的处理方法
  35. function show(user) {
  36. if (url.readyState === 4) {
  37. // 返回的数据在url.responseText
  38. console.log(url.responseText);
  39. // json -> jsobj
  40. const user = JSON.parse(url.responseText);
  41. console.log(user);
  42. document.querySelector("#username").value = user.name;
  43. document.querySelector("#email").value = user.email;
  44. }
  45. }
  46. </script>

  • POST请求

    POST请求比GET请求就只多了一步:需要设置请求头: setRequestHeader()
    GET 请求,需要设置一个请求头,指明数据以哪种格式发送到服务器端
    其他四步和GET大同小异
    共有三种方式:通过表单form属性 enctype 可以查看到

      1. 创建请求对象: new XMLHttpRequest()
      1. 监听请求回调: onreadystatechange()
      1. 初始化请求参数: open(请求类型,请求地址,是否异步)
      1. 设置请求头: setRequestHeader()
      1. 发送请求: send(data)

        设置请求头的时候建议多增加一步,charset=utf-8
        最后请求头设置为:
        .setRequestHeader("content-type","编码格式;charset=utf-8")
        编码格式:content-type: 1.application/x-www-form-urlencoded 2.text-plain 3.application/jsonjson方式发送数据,但json方式只支持utf-8
  1. <script>
  2. // 1.创建请求对象
  3. const url = new XMLHttpRequest();
  4. // 2.监听请求回调
  5. url.addEventListener("readystatechange", show, false);
  6. // 3.初始化请求
  7. url.open("POST", "http://baidu.com", true);
  8. // 4.设置请求头
  9. // 以表单键值对的方式发送数据
  10. url.setRequestHeader("content-type", "application/x-www-form-urlencoded");
  11. // 5.发送请求
  12. url.send(null);
  13. // 回调函数处理办法:
  14. function show(ev) {
  15. if (url.readyState === 4) {
  16. // 值从responseText之中拿
  17. console.log(url.responseText);
  18. }
  19. }
  20. </script>


利用 JS 对象模拟表单数据

  1. // 用js对象来模拟表单数据
  2. const user = {
  3. email: "admin@php.cn",
  4. password: "123456",
  5. };
  6. // 前端是 js, 后端 php, php不能识别 js 对象,只能识别 json
  7. let data = JSON.stringify(user);
  8. // 4. 发送请求: `send()`
  9. url.send(data);

使用json来发送数据的话就要修改请求头格式,以json格式发送

  1. // 4. 设置请求头: `setRequestHeader()`
  2. // 以json格式发送数据, json只支持utf-8
  3. xhr.setRequestHeader("content-type", "application/json;charset=utf-8");

FormData

FormData:将数据封装后发送。
操作步骤:

  1. // 1.拿到表单和按钮
  2. const form = document.querySelector("form");
  3. const btn = document.querySelector("button");
  4. // 2.创建请求对象
  5. const url = new XMLHttpRequest();
  6. // 按钮点击事件
  7. btn.addEventListener("click", callback, false);
  8. // 将事件封包到一个表单之中
  9. function callback(ev) {
  10. // 3.监听请求回调
  11. url.addEventListener("readystatechange", show, false);
  12. // 4.初始化请求参数
  13. url.open("POST", "http://demo.io/data/test1.php", true);
  14. // 5.设置请求头
  15. url.setRequestHeader("content-type", "application/json");
  16. // 6.发送请求(使用FormData()来发送当前表单)
  17. url.send(new FormData(form));
  18. }
  19. // 请求的回调
  20. function show() {
  21. if (url.readyState === 4) {
  22. console.log(url.responseText);
  23. }
  24. }

跨域请求 JSONP

1. 跨域请求

  • 为了安全, 通过脚本发起的请求必须基于”同源策略”
  • 浏览器禁止使用 JS 脚本(Ajax)发起跨域请求(跨域资源共享)
  • 但是通过 html 标签跨域请求不能禁止的,毕竟这是互联网发明初衷

2. 同源策略

  • 协议, 域名, 端口完全相同, 则认为他们遵循了”同源策略”

    同源必须是协议httphttps,域名,端口都一直才叫同源,否则就不是同源

  1. # 协议不同
  2. https://www.caidu.cn:443 /course/812.html
  3. http:// www.caidu.cn:443 /course/812.html
  4. # 端口不同
  5. http://www.caidu.cn:80 /wenda/165068.html
  6. http://www.caidu.cn:8080 /wenda/165068.html
  7. # 域名不同
  8. http://www.caidu.net:80 /wenda/165068.html
  9. http://www.caidu.cn:80 /wenda/165068.html

3.跨域请求实现方法之一:JSNOP(最广泛)

4. JSONP:(JSON with Padding)

jsonp 仅限于GET方式
jsonp:重点在于 Url 的参数中必须要有一个回调参数
动态生成标签,标签必须要有src属性,如<img><script><ifarme>

为什么要使用跨域 JSONP?
Ajax 直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web 服务、WCF,只要是跨域请求,一律不准,但是在 Web 页面上调用 JS 文件则不守是否跨域的影响。恰巧 json 就是一种通用的跨编程语言的轻量级数据交换/传输/存储格式,是一种纯字符类语言,我们可以随意调用和处理数据。

跨域请求的原理:

  1. 将数据封装到 JS 文件之中
  2. 在本地动态生成一个带有src属性的标签,调用服务端的 JS
  3. 本地通过该标签调用服务端的JS文件
  4. 服务端将数据通过回调函数将数据以Json格式传递给前端解析
  5. 调用成功

实例:

  • script标签允许跨域请求脚本: <script src="...."></script>
  • 动态生成<script>元素,并将需要跨域访问的 URL,赋值给 script 元素的 src 属性
  • 在跨域访问的服务器脚本中(如 php),将数据转为 json 格式,直接返回给前端处理就可以了
  • 原理就是这么简单,下面我们来实例演示
  • 创建一个站点:blog.io,并指向到当前项目的一个目录中,例如blog

回调函数和属性名(以名值对的方式向服务器发送给请求):

  1. <!DOCTYPE html>
  2. <html lang="">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>JSONP跨域请求</title>
  7. <style>
  8. form {
  9. display: inline-grid;
  10. grid-template-columns: 5em 15em;
  11. gap: 1em;
  12. padding: 1em;
  13. border: 1px solid #000;
  14. background-color: lightcyan;
  15. }
  16. form button {
  17. grid-area: auto / 2 / auto / span 1;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <form action="" onsubmit="return false;">
  23. <label for="username">用户名:</label>
  24. <input type="text" id="username" name="username" />
  25. <label for="email">邮箱:</label>
  26. <input type="email" id="email" name="email" />
  27. <button>保存</button>
  28. </form>
  29. <hr />
  30. <button id="jsonp">JSONP跨域请求</button>
  31. <script>
  32. // 拿到按钮的bom属性
  33. const btn = document.querySelector("#jsonp");
  34. // 监听按钮的点击事件
  35. btn.addEventListener("click", creatScript, false);
  36. // createScirpt()动态创建<script>
  37. function creatScript() {
  38. // 这里的url内的show就相当于callback函数
  39. // 以get方法添加查询参数,就是放在url中,以键值对方式添加每个键值对之间用&分割
  40. let url = "http://blog.io/index.php?id=3&jsonp=show";
  41. // 生成script元素
  42. const script = document.createElement("script");
  43. // 将跨域请求的url赋值给src属性
  44. script.src = url;
  45. // 将script添加到页面之中
  46. document.head.appendChild(script);
  47. }
  48. // 回调函数show,为什么是show,请看url,我们定义了一个callback返回函数接收数据
  49. function show(user) {
  50. // 服务端返回的数据以及自动解析为了JS对象,所以可以直接引用
  51. console.log(user);
  52. document.querySelector("#username").value = user.name;
  53. document.querySelector("#email").value = user.email;
  54. }
  55. </script>
  56. </body>
  57. </html>

服务端代码:

  1. <?php
  2. $users = [
  3. ['id'=>1, 'name'=>'admin', 'email'=>'admin@php.cn'],
  4. ['id'=>2, 'name'=>'peter', 'email'=>'peter@php.cn'],
  5. ['id'=>3, 'name'=>'jack', 'email'=>'jack@php.cn'],
  6. ];
  7. // 查询条件
  8. // 通过前端发送请求的url内的id来查询
  9. $id = $_GET['id'];
  10. // js回调
  11. $callback = $_GET['jsonp'];//回调变量名:可在前端跨域请求url之中查看到
  12. foreach ($users as $user) {
  13. if ($user['id'] == $id) {
  14. $result = $user;
  15. break;
  16. }
  17. }
  18. $data = json_encode($result);
  19. // 创建一条js函数的调用语句返回
  20. // echo "函数名(参数)";
  21. echo "{$callback}({$data})";

最终跨域拿到数据:

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议