《JSON 必知必会》阅读摘要记录

JSON 必知必会书籍学习记录笔记,想深入一下JSON Hijacking 漏洞,所以就打算找一本JSON的书籍来读一遍,打捞自己的基础,于是就选了这本书来学习,以后这种读书笔记的方式可能还会坚持下去,这样可以逼自己养成阅读的习惯,顺便又写了博客,何乐不为呢?

书籍简介

作者: [美] Lindsay Bassett
译者: 魏嘉汛
出版年: 2016-5
页数: 128
定价: 35.00元
装帧: 平装
丛书: 图灵程序设计丛书·Web开发系列
ISBN: 9787115422071

第1章 什么是JSON

JSON 是一种轻量的数据格式,在各种地方传递数据。

1.1 JSON是一种数据交换格式

数据交换格式是一种在不同平台间传递数据的文本格式。除 JSON 外,常用的还有XML数据交换格式。

1.2 JSON独立于编程语言

JSON 的全称是 JavaScript Object Notation(JavaScript 对象表示法),JSON 虽然源于 JavaScript 的一个子集,但是对JS不熟悉的话问题也不大,因为JSON现在也被广泛地应用于其他的编程语言中。

第2章 JSON语法

2.1 JSON基于JavaScript对象字面量

JSON 中并不会涉及 JavaScript 对象 字面量中的函数。JSON 所基于的 JavaScript 对象字面量单纯指对象字面量及 其属性的语法表示。这种属性表示方法也就是通过名称 - 值对来实现的。

使用JSON描述我现在穿的鞋子

{
  "brand": "Crocs", 
  "color": "pink", 
  "size": 9, 
  "hasLaces": false
}

2.2 名称-值对

名称 - 值对的概念非常流行。它们也有别的名字,像键 - 值对、属性 - 值对或字段 - 值对等

JSON 中使用冒号:来分隔名称和值。名称始终在左侧始终在右侧

2.3 正确的JSON语法

JSON中的 名称 必需要用双引号包裹,为了代码友好和可移植性,名称 - 值 中尽量避免使用空格或特殊字符。

属性名可以包含下划线数字,但是在使用多个单词的时候,推荐使用驼峰命名法,比如下面这样:

"myAnimal": "cat"

值是字符串时,必须使用双引号包裹。

而在 JSON 中,还 有数字、布尔值、数组、对象、null 等其他数据类型,这些都不应被双引号 包裹,这些格式下面的章节会讲解。下面字符提供的是告诉机器如何读取数据的指令:

  • { 开始读取对象
  • }结束读取对象
  • [开始读取数组
  • ]结束读取数组
  • :在名称 - 值对中分隔名称和值
  • ,分隔对象中的名称 - 值对 或者 分隔数组中的值 也可以认为是 一个新部分的开始

这不是合法的 JSON

{
  'title': 'This is my title.',
  'body': 'This is the body.' 
}

在 JSON 中, 名称 必需要用双引号包裹

合法的 JSON

{
  "title": "This is my title.",
  "body": "This is the body." 
}

2.4 语法验证

很多IDE自带了JSON语法验证,我们敲错的时候回报错,本书中还提到了一些在线的工具地址,用户JSON格式校验和代码高亮美化,这里国光我就不推荐了。VSCode里面都集成了,用起来更舒服一点。

2.5 JSON文件

JSON的文件扩展名:.json

国外人写书也太详细了吧,这个都要写出来

2.6 JSON的媒体类型

传递数据时,需要提前告知接收方数据是什么类型,也就是我们常用的 MIME 类型

JSON 的 MIME 类型是 application/json

一个比较全面的MIME表:http://www.iana.org/assignments/media-types/

第3章 JSON的数据类型

数据类型是学习各种编程语言老生常谈的问题,语言是想通的,有其他编程语言基础的话,这里学起来就会很轻松。

3.1 数据类型简介

不同类型的数 据有着不同的操作途径,可以让两个数相乘,但是不能让一个单词和一个 数相乘。

在计算机科学中,有一种数据类型被称为原始数据类型,是最基本的一种类型:

  • 数字(如 5 或 5.09)

    – 整型

    – 浮点数

    – 定点数

  • 字符和字符串(如“a”“A”或“apple”)

  • 布尔类型(即真或假)

除了原始数据类型,大多数编程语言中还有许多其他的类型,它们尝尝被称为复合数据类型

枚举数据类型是编程语言中常见的复合数据类型之一,是一个可以枚举的数据结构。

枚举类型 Demo

[
"witty", "charming", "brave", "bold"
]

另一种复合数据类型是对象数据类型,这个之前我们已经见过它了:

{
  "brand": "Crocs", 
  "color": "pink", 
  "size": 9, 
  "hasLaces": false
}

3.2 JSON中的数据类型

JSON的数据类型 在其他语言中的支持度也很高。

JSON 中的数据类型包括:

  • 对象
  • 字符串
  • 数字
  • 布尔值
  • null
  • 数组

3.3 JSON中的对象数据类型

JSON 本身就是对象,也就是一 个被花括号包裹的名称 - 值对的列表。

下面代码展示了如何用嵌套对象来描述一个人:

{
  "person": {
    "name": "Lindsay Bassett",
    "heightInInches": 66, 
    "head": {
      "hair": {
        "color": "light blond",
        "length": "short",
        "style": "A-line" 
      },
      "eyes": "green" 
    }
  } 
}

3.4 JSON中的字符串类型

JSON 中的字符串可以由任何 Unicode 字符构成,字符串的两边必须被双引号包裹。当值里面出现双引号的时候,我们需要在双引号前面加上一个反斜线字符来对其转义:

{
    "promo": "Say \"Bob's the best!\" at checkout for free 8oz bag of kibble."
}

此外 反斜线本身也需要转义。

在这段代码中使用反斜线会报错

{
    "location": "C:\Program Files"
}

反斜线需要另一个反斜线来转义

{
    "location": "C:\\Program Files" 
}

除了双引号和反斜线,还需要转义以下字符:

  • \/(正斜线)
  • \b(退格符)
  • \f(换页符)
  • \t(制表符)
  • \n(换行符)
  • \r(回车符)
  • \u 后面跟十六进制字符(如笑脸表情 \u263A)

3.5 JSON中的数字类型

JSON 中的数字表示


{
  "widgetInventory": 289, 
  "sadSavingsAccount": 22.59, 
  "seattleLatitude": 47.606209, 
  "seattleLongitude": -122.332071, 
  "earthsMass": 5.97219e+24
}

JSON 中的数字可以是整数、小数、负数或者指数。

3.6 JSON中的布尔类型

在一些编程语言中,true 的字面值可能用 1 来表示,false 用 0 来表示,有时候字面值也可能是大写或小写的单词,比如 true 或 TRUE,false 或 FALSE。

但是在JSON中仅使用小写形式:truefalse,任何其他 形式的写法都会报错。

{
  "toastWithBreakfast": false,
  "breadWithLunch": true 
}

3.7 JSON中的null类型

在编程中,null 就用来表 示 0、一无所有、不存在等意思,而不用数字来表示。

在 JavaScript 中,undefined 是在尝试获取一些不存在的对象或变量时返回的结果,undefined 与那些声 明的名称和值都不存在的对象或变量有关,而 null 则仅与对象或变量的值 有关。null 是一个表示“没有值”的值。在 JSON 中,null 必须使用小写 形式。

3.8 JSON中的数组类型

{
  "eggCarton": [
      "egg", "egg", "egg", "egg", "egg", 1, 2, 3
  ] 
}

数组 始终应被方括号[]包裹。在数组中,可以看到一个列表,列表项之间 用,隔开,列表中的值可以是任何合法的 JSON 数据类型(字符串、数 字、对象、布尔值、数组以及 null),在JSON中的值可以混合使用不同的数据类型。

第4章 JSON Schema

数据通过互联网或其他网络传输到接收方的过程中可能会出错,所以就需要对数据进行验证。早在 JSON 出现以前,这样的情况就已经存在于数据交换之中。幸运的是, 技术从业者都是擅长解决问题的人,Schema(意为模式)这一概念也随之 诞生。

4.1 验证的魔力

数据验证很重要,生活中很多场景都需要数据验证,JSON也是如此,以保证数据符合要求。

4.2 JSON Schema简介

尽管 JSON 已经相当成熟,但 JSON Schema 仍在开发之中。

JSON Schema 使用 JSON 来书写,所以仅需几步就能掌握它。

要 在 JSON 第一个名称 - 值对中,声明其为一个 schema 文件:

声明的名称必须为 “$schema”,值必须为所用草拟版本的链接

{
    "$schema": "http://json-schema.org/draft-04/schema#" 
}

第二个名称 - 值对应该是 JSON Schema 文件的标题

表示一只猫的 JSON Schema 文件格式

{
  "$schema": "http://json-schema.org/draft-04/schema#", 
    "title": "Cat"
}

在 JSON Schema 文件的第三个名称值对中,要定义需要在 JSON 中包含的 属性。”properties” 的值实质上是我们想要的 JSON 的名称 - 值对的骨架。 我们没有使用字面量,而是使用了一个对象来定义数据类型,并有选择地 进行描述:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Cat",
  "properties": {
      "name": {
        "type": "string" 
      },
      "age": {
        "type": "number",
        "description": "Your cat's age in years."
      }, 
      "declawed": {
        "type": "boolean"
         }
      } 
}

接下来就能验证 JSON 是否符合 JSON Schema

这个 JSON 符合针对猫定义的 JSON Schema

{
  "name": "Fluffy",
  "age": 2, 
  "declawed": false
}

可以验证表示“Fluffy”这只猫的 JSON 中的 name、age 和 declawed 是否都有正确类型的值。

此外还可以验证

  1. 是否包含所需要的数据?
  2. 值的形式是不是我需要的?

这里开发相关,国光我这里就不重点说这块内容了,感兴趣的话可以在原书本中找到答案。

第5章 JSON中的安全问题

JSON 本身不会构成什么威胁,毕竟它只是一种数据交换格式。它不过是一 种数据文件,或者说数据流。真正会产生安全问题的是 JSON 的使用。本 章重点讨论在 Web 中使用 JSON 时最常见的两个安全问题: 跨站请求伪造跨站脚本攻击。 好激动,终于到安全部分的知识了!!!

5.1 客户端和服务端的关系

互联网浏览器和网站之间的关系就像我和餐厅的关系一样。这一关系包含 了大量的请求和响应。我的请求是一份晚餐,厨房的响应则是将我点的菜 做出来并送到我的面前。

5.2 跨站请求伪造

跨站请求伪造,即 CSRF(cross-site request forgery,读作 sea-surf),是一种 利用站点对用户浏览器信任而发起攻击的方式。CSRF 漏洞已经存在了很长 时间,远比 JSON 出现得早。

接下来看一个利用 JSON 进行 CSRF 攻击的例子。

你登录了一个银行的网站,这个网站有一个关于你的敏感信息的 JSON URL

JSON 中保存的你的敏感信息

[
  {
      "user": "bobbarker" 
  },
  {
      "phone": "555-555-5555"
  } 
]

你可能会说:“嘿,你的 JSON 最外面没加花括号!”其实这里的 JSON 格 式是合法的。不过有些合法的 JSON 十分危险,因为它们也是可以执行的 JavaScript 脚本。本例这种情况也被称为顶层 JSON 数组

本例中的站点使用会话 cookie 验证,以确保信息是传送给像你一样已经注 册且处于登录状态的用户。

而示例中的黑客在发现银行网站上保存敏感信息的 JSON 的 URL 后,会把 它放到指向自己站点的 <script> 标签中。

浏 览 器 对 于 不 同 域 名的站点之间进行资源分享有一定的限制规则。但是<script>是可以加载外部资源的,利用这个特性:

黑客站点的<script> 标签可能是这个样子的

<script src="https://www.yourspecialbank.com/user.json"></script>

这样的攻击能够实现,很关键的一点就是利用了你和网站间的凭证。没有你的凭证,<script> 标签中的链接是不会返回任何东西的。

CSRF 攻击就利用了这一信任关系。黑客为了利用这一信任,需要你在已经 登录银行的情况下访问他含有危险的 <script> 标签的网站。要实现这点, 他会发送大量的伪造邮件,内容大致是“银行提醒您:重要消息”。这类邮 件会伪造得和你的银行(或它们想攻击的网站)发来的邮件一模一样。如 果接收者不好好查看一下发件人,或不仔细查看一下链接是否是指向他们 可以信任的网站,就很可能会点进去。

假如你不小心点击了这个链 接。如果这时你没有退出银行账号,会话就仍然存在。此时你和银行之间 处于信任的关系中。一旦你进入了坏人的网站,意识到这个站点很奇怪, 就关闭了。不过这时已经晚了。黑客已然获取到了敏感的 JSON 数据并发 送到了自己服务器上保存起来。

那么银行及其开发者应如何阻止 CSRF 攻击呢?

首先,银行应该将数组作为一个值存入 JSON 对象。这样数组再是合法的 JavaScript

将数组存放到对象之中,使其成为非法的 JavaScript,这样就不 会被 <script> 标签加载

{
  "info": [
    {
        "user": "bobbarker"
    }, 
    {
        "phone": "555-555-5555" 
    }
  ] 
}

下一步,银行应仅允许 POST 请求获取数据,禁止使用 GET 请求,这样黑客 便无法使用他自己的 URL 中的链接了。如果服务器端允许 GET 请求,就可以直接通过浏览器 或 <script> 标签链接到它。但 POST 则不可以直接被链接到。一旦不能使用 <script> 标签,黑客就会受到资源共享策略的限制,从而无法通过利用银 行对客户端的信任进行欺骗行为。

当然,这并不意味着通过 HTTP 进行的 JSON 数据交换都应通过 POST 来进 行。当JSON存在敏感数据的时候应该考虑使用POST来提交数据,其他不重要的数据 怎么开心怎么写。

5.3 注入攻击

注入攻击包含许多种形式与格式。不过,它们都是利用系统本身的漏洞来 实现的。CSRF 攻击仅包括利用信任机制进行的攻击。注入攻击则主要通过 向网站注入恶意代码来实现。

5.3.1 跨站脚本攻击

跨站脚本攻击(cross-site scripting,XSS)是注入攻击的一种。

JSON 本身仅仅是文本,但是当用户在JavaScript汇总使用 eval() 函数来解析JSON的时候可能出现安全问题,导致XSS漏洞的产生。

随着 JSON 本身的不断发展,这一漏洞已得到公认。JSON.parse() 函数就 是用来处理这一问题的。该函数仅会解析 JSON,并不会执行脚本。

使用 JSON.parse() 代替 eval()

var jsonString = '{"animal":"cat"}'; 
var myObject = JSON.parse(jsonString); 
alert(myObject.animal);

5.3.2 安全漏洞:决策上的失误

有时候危险也会直接包含在合法的 JSON 数据之中。

让我们先来看一些很规矩的 JSON 数据

{
  "message": "hello, world!" 
}

假设我的站点允许一个用户向另一个用户发送可以包含任何内容的消息。

在消息界面, 我从服务端请求 JSON 格式的消息并在客户端使用 eval() 函数来将 JSON转换成可以使用的 JavaScript 对象。然后我将该 JavaScript 对象的 message 属性的值直接显示在 HTML 中。

不那么规矩的 JSON

{
    "message": "<div onmouseover=\"alert('gotcha!')\">hover here.</div>"
}

这样就直接导致了XSS漏洞的产生,问题出在最后JSON数据输出的时候 导致了XSS漏洞的产生,虽然传输的时候很安全,但是最后显示在了HTML页面上。和我以前遇到的这个漏洞原理一样:记录一次某客户系统的漏洞挖掘 XSS1

如何阻止这种情况呢?一方面,可以采取一些手段使得消息中不包含 HTML,将HTML特殊字符实体化编码来修复这个问题。

第6章 JavaScript中的XMLHttpRequest与Web API

JavaScript 中的 XMLHttpRequest 与 Web API 等概念听上去好像很难,但实 际上并没有想象中那么复杂。它仅仅是一种简单的客户端与服务端的关系。

JavaScript 中的 XMLHttpRequest 负责在客户端发起请求,而 Web API 负责在 服务端返回响应。

6.1 Web API

JSON 资源可以通过一个 URL 来请求,Web API就是这个URL,负责返回给客户JSON格式的信息,然后客户端再解析这串JSON数据来达到数据显示的效果。

6.2 JavaScript中的XMLHttpRequest对象

尽管 JavaScript 的 XMLHttpRequest 对象听上去和 XML 有关,但实际上我们 使用它来发起 HTTP 请求。

JavaScript 中使用协议来发送这类请求的代码就是 XMLHttpRequest。 JavaScript 是一种面向对象的语言,而 XMLHttpRequest 就是一类对象。

JavaScript 中的 XMLHttpRequest 对象

var myXmlHttpRequest = new XMLHttpRequest();

这个对象的熟悉比较复杂和混乱,国光这里就不深入了。

6.3 混乱的关系与共享的规则

我在这里留给了你一些悬念。我展示了一些能够运行的代码,但是它们违 背了浏览器的同源策略。它们本来不应该跑通,但是却跑通了,这是因为开发者们绕过了一些限制。

6.3.1 跨域资源共享

有些开发人员可以连续多年通过 JavaScript 的 AJAX 技术向公共 API 发送请 求,而不会受到同源策略的影响。这是因为这些公共 API 的开发者在他们 的服务器上实现了跨域资源共享(cross-origin resource sharing,CORS)。

这 些服务器会在响应头额外加上一些带有 Access-Control-Allow 前缀的属性:

API 返 回 的 响 应 头 中 的 Access- Control-Allow 部分

Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST 
Access-Control-Allow-Origin: *

这些头部定义了

证书是否可用,

哪些 HTTP 方法(GET、POST、PUT、DELETE、 HEAD、OPTIONS、TRACE、CONNECT)是可用的,

以及最重要的一点,即允许哪些域名,本例中,此处包含一个星号*。它表示任意域名都是允许的。

CORS 还可用于禁止某些域名的 访问,来防止有些人用 API 做坏事,如 CSRF:

使用 CORS 进行安全防护

Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: http://www.somebank.com

我们仅允许通过 POST 方式请求资源,禁止除 http://www.somebank.co以外的站点去获取资源

使用 CORS 也会遇到一些问题,而且也不是所有的 JSON 数据都是从标准 的 Web API 获取的。

例如可能你有两个域名不同的站点(http://a.comhttp://b.com), 且 想 让 http://a.comhttp://b.com 共享一些 JSON 文件,这就需要使用 JSON-P 了。

6.3.2 JSON-P

JSON-P 指带有 padding(内联) 的 JSON。我在第 5 章提到过 <script> 标签不受同源策略的影响。JSON-P 就是利用这一点来向不同域名的站点请求 JSON 的。

JSON-P 并没有 CORS 那么理想,它只是一个备选方案(CORS 是更好的 方案,同时也是一种标准),但有时候还是需要这种解决方案的。

JSON-P 中的padding(内联)非常简单,就是将 JavaScript 加入 JSON 文 档。

JSON-P

getTheAnimal(
  {
    "animal": "cat" 
  }
);

内联于 JSON 文档的 JavaScript 调用了一个函数,函数参数是 JSON。函数 参数提供了一种将数据传递给函数的方式。该函数是在客户端的 JavaScript 代码中定义的

在 JavaScript 中声明的函数

function getTheAnimal(data) {
    var myAnimal = data.animal;  // will be "cat"
}

当在 JavaScript 中声明该函数之后,需要进行一些设置。这部分就体现出 了 JSON-P 是如何利用 <script> 标签不受同源策略影响这一点的

创建 <script> 标签,并将其动态添加到 HTML 文档的 <head> 标签中

var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://notarealdomain.com/animal.json"; 
document.getElementsByTagName('head')[0].appendChild(script);

服务端也需要对 JSON-P 提供一定的支持,它应允许用户自定义函数的名 字。它通常是作为 URL 中 callback 的参数传递的。

通过 callback 告知服务器函数的名字

script.src = "http://notarealdomain.com/animal.json?callback=getThing";

服务端会根据 callback 参数的值来动态地为在 JSON 中内联的函数命名。

JSON-P 中动态命名的函数

getThing( 
  {
    "animal": "cat" 
  }
);

JSON-P 还需要服务端的不少支持,因为 JSON 资源必须包含 JavaScript 内 联。不管是使用 CORS 还是 JSON-P,都离不开服务端的支持。因此,客户端跨域的 XMLHttpRequest 需要服务端的支持来保证 JSON 资源请求成功。

6.3.3 知乎JSONP 的工作原理是什么?

书本这章看完了我对JSONP的理解还是有很多不明白的地方,本小节是国光自己知乎找的理解。

贺师俊 JavaScrip、前端开发、CSS等 4 个话题的优秀回答者

很简单,就是利用<script>标签没有跨域限制的“漏洞”(历史遗迹啊)来达到与第三方通讯的目的。

当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形如:

 <script src="http://www.example.net/api?param1=1&param2=2"></script>   

并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。

第三方产生的响应为JSON数据的包装(故称之为JSON,即JSON padding),形如

callback({"name":"hax","gender":"Male"}) 

这样浏览器会调用callback函数,并传递解析后JSON对象作为参数。

本站脚本可在callback函数里处理所传入的数据。

Ddd Poplar

JSONP是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

黄之昊 手艺人/前端

JSON 是一种数据格式
JSONP 是一种数据调用的方式。

你可以简单的理解为 带callback的JSON就是JSONP

柴郡猫Kate 程序员

JSONP利用<script>标签引用资源不受同源策略的影响的特性,向服务器端发送请求时在url中拼接一个callback函数,然后将服务器端的返回作为callback函数的参数进行调用,从而达到跨域资源请求的目的。

示例:

var callbackHandler = function(data) {
    process(data) //对返回数据进行处理
}

<script src="http://xxx.com/xxx?callback=callbackHandler" />

6.3.4 博客园 JSON与JSONP讲解

知乎看完了,貌似对JSONP懂一点了,但还是有疑惑,于是看了网友们推荐的这篇文章:

【原创】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例

JSON是一种数据交换格式,而JSONP是一种非官方跨域数据交互协议。一个是描述信息的格式,一个是信息传递双方约定的方法。

JSONP怎么产生的

Ajax直接请求普通文件存在跨域无权限访问的问题

Web页面上调用js文件时则不受是否跨域的影响 我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<script><img><iframe>

纯web端跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理

JSON的纯字符数据格式可以简洁的描述复杂数据,而且被原生JS支持

Web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。

客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据

JSONP的客户端具体实现

远程服务器remoteserver.com根目录下有个remote.js文件代码如下:

alert('我是远程文件');

本地服务器localserver.com下有个jsonp.html页面代码如下:

<script src="http://remoteserver.com/remote.js"></script>

毫无疑问,页面将会弹出一个提示窗体,表明跨域调用成功。

现在我们在jsonp.html页面定义一个函数,然后在远程remote.js中传入数据进行调用。

jsonp.html页面代码如下:

<script>
var localHandler = function(data){
    alert('我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:' + data.result);
};
</script>

<script src="http://remoteserver.com/remote.js"></script>

remote.js文件代码如下:

localHandler({"result":"我是远程js带来的数据"});

运行之后查看结果,页面成功弹出提示窗口,哇塞 好神奇!显示本地函数被跨域的远程js调用成功,并且还接收到了远程js带来的数据。

很欣喜,跨域远程获取数据的目的基本实现了,但是又一个问题出现了,我怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是JSONP的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?我们接着往下看。

聪明的开发者很容易想到,只要服务端提供的js脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端“我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来生成js脚本并响应了。

jsonp.html页面的代码:

<script>
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
    alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};

// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://a.com/api.php?code=CA1998&callback=flightHandler";

// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);

// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script); 
</script>

这次的代码变化比较大,不再直接把远程js文件写死,而是编码实现动态查询,而这也正是jsonp客户端实现的核心部分,本例中的重点也就在于如何完成jsonp调用的全过程。

我们看到调用的url中传递了一个code参数,告诉服务器我要查的是CA1998次航班的信息,而callback参数则告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用。

OK,服务器很聪明,这个叫做api.php的页面生成了一段这样的代码提供给jsonp.html(服务端的实现这里就不演示了,与你选用的语言无关,说到底就是拼接字符串):

flightHandler({
    "code": "CA1998",
    "price": 1780,
    "tickets": 5
});

我们看到,传递给flightHandler函数的是一个json,它描述了航班的基本信息。运行一下页面,成功弹出提示窗口,JSONP的执行全过程顺利完成!

到这里为止的话,相信你已经能够理解jsonp的客户端实现原理了吧?剩下的就是如何把代码封装一下,以便于与用户界面交互,从而实现多次和重复调用。

什么?你用的是jQuery,想知道jQuery如何实现jsonp调用?好吧,那我就好人做到底,再给你一段jQuery使用JSONP的代码(我们依然沿用上面那个航班信息查询的例子,假定返回JSONP结果不变):

<script src="jquery.min.js"></script>
<script>
    jQuery(document).ready(function(){ 
    $.ajax({
         type: "get",
         async: false,
         url: "http://a.com/api.php?code=CA1998",
         dataType: "jsonp",
         jsonp: "callback", //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
         jsonpCallback:"flightHandler", //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
         success: function(json){
             alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
         },
         error: function(){
             alert('fail');
         }
     });
    });
</script>

是不是有点奇怪?为什么我这次没有写flightHandler这个函数呢?而且竟然也运行成功了!哈哈,这就是jQuery的功劳了,jQuery在处理JSONP类型的ajax时(还是忍不住吐槽,虽然jquery也把JSONP归入了ajax,但其实它们真的不是一回事儿),自动帮你生成回调函数并把数据取出来供success属性方法来调用,是不是很爽呀?

!!! 国光我看懂了,顿时豁然开朗,以后写文章也要向这位博主学习,把知识讲的生动形象,浅显易懂。

第7章 JSON与客户端框架

如今,有许多(>50)种 JavaScript 框架可供选择,让我们来了解一些 JavaScript 框架,以及它们与 JSON 的关系。

7.1 jQuery和JSON

jQuery可以让开发者操作DOM更简单,比如将一个 HTML 元素隐藏。

先创建一个按钮,然后隐藏它

一个在浏览器中显示为“My Button”的按钮

<button id="myButton">My Button</button>

为使用 JavaScript 代码隐藏这个按钮,首先要调用 HTML 的 document 对象的 getElementById(id) 方法,然后将对应的 style.display 属性值设为 "none"

用于隐藏“My Button”的 JavaScript 代码

document.getElementById("myButton").style.display = "none";

若使用 jQuery,可以用不到上例一半长度的代码实现同样的功能

用于隐藏“My Button”的 jQuery 代码

$("#myButton").hide();

jQuery的兼容性也很好,在第 5 章中我用 更为安全的 JSON.parse() 方法代替 eval() 方法来解析 JSON,但是老版本的浏览器不支持这种安全的方法,这里jQuery 有自己的解析 JSON 的方法:用 jQuery.parseJSON 函数。

使用 JavaScript 中的 JSON.parse() 解析 JSON

var myAnimal = JSON.parse('{ "animal" : "cat" }');

使用 jQuery 内置的 jQuery.parseJSON 来解析 JSON

var myAnimal = jQuery.parseJSON('{ "animal" : "cat" }');

上面的例子中,使用 jQuery 并没有在代码长度上面体现出优势。但是这里是兼容老版本浏览器的,如果深入研究下去的话 会发现它会先尝试使用原生的 JSON.parse() 函数。 如果浏览器不支持,它会使用和eval()功能类似的new Function()。同时, 它会对一些不合法的字符进行检测,如果发现其中有注入攻击的威胁,就 会抛出错误。

除了jQuery.parseJSON以外,还有一个用于通过 HTTP 请求 JSON 的函数。

回顾第 6 章,在使用 JavaScript 进行 HTTP 请求时,写了不少代码。

创建一个新的 XMLHttpRequest 对象并从 OpenWeatherMap API 获 取 JSON

var myXMLHttpRequest = new XMLHttpRequest();
var url = "http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139";

myXMLHttpRequest.onreadystatechange = function() {
  if (myXMLHttpRequest.readyState === 4 && myXMLHttpRequest.status
  === 200) {
    var myObject = JSON.parse(myXMLHttpRequest.responseText); 
    var myJSON = JSON.stringify(myObject);
  } 
}
myXMLHttpRequest.open("GET", url, true); 
myXMLHttpRequest.send();

使用 jQuery 仅需几行代码即可完成对 JSON 数据的请求

这段 jQuery 代码创建一个新的 XMLHttpRequest 对 象并获取 JSON 数据,还将 JSON 数据反序列化为一个 JavaScript 对象

var url = "http://api.openweathermap.org/data/2.5/ weather?lat=35&lon=139";
$.getJSON(url, function(data) {
// 对天气数据执行一些操作 });
});

jQuery 真的很方便呐!

7.2 AngularJS

jQuery 框架是为 DOM 操作服务的抽象化工具,AngularJS 框架是专注于创建单页应用的抽象化工具。

这里国光认为还是jQuery用的比较多,所以这里我就不再多花时间了,等以后转行做开发了再考虑看看。

第8章 JSON与NoSQL

NoSQL,顾名思义,它不是一种关系型数据库。我们不能使用 SQL 从 关联在一起的数据库表格的行和列中获取数据。

NoSQL 数据库的一个例子是键值对存储。键值对存储模型将数据简化为键 值对。如果要将英语词典编入数据库,那么用键值对存储非常合适。每一 个单词就是一个键,单词对应的定义就是键的值。对于比较简单的数据结 构来说,使用这种数据库比使用传统的关系型数据库要合适。

本章我们来看一种使用 JSON 文档存储数据的文档存储数据库——CouchDB。

8.1 CouchDB数据库

CouchDB 是一种使用 JSON 文档存储数据的NoSQL 数据库。

使用数组中的对象来表示账户和地址间的一对多关系。

使用 JSON 文档来表示账户

{
  "firstName": "Bob", 
  "lastName": "Barker", 
  "age": 91, 
  "addresses": [
    {
    "street": "123 fake st",
      "city": "Somewhere",
      "state": "OR",
      "zip": 97520
    }, 
    {
      "street": "456 fakey ln", 
      "city": "Some Place", 
      "state": "CA",
      "zip": 96026
    } 
  ]
}

由于 CouchDB 使用文档来存储数据,因此当我从数据库中查询一个账户时, 得到的直接就是一个结构化的文档。没有必要进行重组。这样既高效又方便。

但是在更复杂的数据情况下,还是老老实实使用关系型数据库吧,用这种文档来表示就很蛋疼了。

CouchDB可以很方便地添加字段,无需结构改动。

那么问题来了,该怎么把 数据放进去,又怎么把数据拿出来? CouchDB 使用基于 HTTP 的 API 实现 这一功能。现在来看看 CouchDB API。

8.2 CouchDB API

CouchDB API的默认端口是5984,查了下 果然这个端口历史上存在未授权访问漏洞,并且还可以造成命令执行…

以后这个端口的话 就知道了,还有这种操作。

这个章节说了如何使用用这个CouchDB API,国光这里暂时不深入,以后有空了再详细阅读。

第9章 服务端的JSON

当谈及 Web 客户端 - 服务端关系时,可以将技术按客户端和服务端的区别 分类。

• 客户端:HTML、CSS、JavaScript。
• 服务端:PHP、ASP.NET、Node.js、Ruby on Rails、Java、Go,等等

书里面居然没有Python… 尴尬

在 Web 客户端,我们通过 HTTP 向服务端发送资源请求。服务端会响应一 份文档,如 HTML 或 JSON。当文档是 JSON 时,必须要用服务端代码来 生成它。

不过,JavaScript 并不是唯一一个可以通过 HTTP 请求获取 JSON 资源的语言。服务端的 Web 框架也可以发起 HTTP 请求。

当通过服务端技术来请求 JSON 时,服务端扮演的其实是客户端的角色。 下面列举了一些需要用服务端 Web 框架发送 HTTP 请求的例子。

9.1 序列化、反序列化与请求JSON

大部分服务端 Web 框架以及脚本语言都较好地支持 JSON

9.1.1 ASP.NET

.NET 这个古老的语言要凉,国光这里就不浪费时间了 直接跳过

9.1.2 PHP

表示一只猫的一个 PHP 类

class Cat {
    public $name;
    public $breed;
    public $age;
    public $declawed;
}

类的实例化意味着对象的创建。之后该对象便可在编程逻辑中使用

将类实例化并设置属性。这意味着对象被创建了。最后一行会 输出 “Fluffy Boo”

$cat = new Cat(); 
$cat->name = "Fluffy Boo"; 
$cat->breed = "Maine Coon"; 
$cat->age = 2.5; 
$cat->declawed = false;

echo $cat->name;

PHP 对 JSON 的序列化和反序列化操作也有内置的支持。这类操作在 PHP 中称为 JSON 的编码解码

因此,序列化 JSON 时应调用 json_encode 函数,反序列化 JSON 时应调用 json_decode 函数。

1. 序列化JSON

在 PHP 中,可以通过内置的 JSON 支持快速地将 PHP 对象序列化。这一部分中,我们将创建一个保存地址信息的 PHP 对象,并将其序列化为 JSON。

创建并序列化一个账户

<?php
class Account {
    public $firstName;
    public $lastName;
    public $phone;
    public $gender;
    public $addresses;
    public $famous;
}
class Address {
    public $street;
    public $city;
    public $state;
    public $zip;
}
$address1 = new Address();
$address1->street = "123 fakey st";
$address1->city = "Somewhere";
$address1->state = "CA";
$address1->zip = 96027;

$address2 = new Address();
$address2->street = "456 fake dr";
$address2->city = "Some Place";
$address2->state = "CA";
$address2->zip = 96345;

$account = new Account();
$account->firstName = "Bob";
$account->lastName = "Barker";
$account->gender = "male";
$account->phone = "555-555-5555";
$account->famous = true;
$account->addresses = array($address1, $address2);

$json = json_encode($account);

?>

json_encode($account) 返回的结果

{
    "firstName": "Bob",
    "lastName": "Barker",
    "phone": "555-555-5555",
    "gender": "male",
    "addresses": [{
            "street": "123 fakey st",
            "city": "Somewhere",
            "state": "CA",
            "zip": 96027
        },
        {
            "street": "456 fake dr",
            "city": "Some Place",
            "state": "CA",
            "zip": 96345
        }
    ],
    "famous": true
}

2. 反序列化JSON

使用 json_ decode 函数来反序列化 JSON。不过,内置的方法并不支持将 JSON 反序列 化为某种具体的 PHP 对象类型,如 Account 类。所以,需要采取一些措施 将数据重塑为对应的 PHP 对象。

首先给 Account 对象添加一个新函数,使它可以通过 JSON 字符串设置自己 的属性。

示例中,loadFromJSON 函数接受一个 JSON 字符串作为参数,它会调 用内置的json_decode 函数反序列化一个一般的 PHP 对象,然后在 foreach 循环中遍历该对象的属性,并赋值给 Account 对象中名称相同的属性。

向 Account 对象添加一个函数

class Account {
    public $firstName;
    public $lastName;
    public $phone;
    public $gender;
    public $addresses;
    public $famous;
    public function loadFromJSON($json) {
        $object = json_decode($json);
        foreach ($object AS $name => $value) {
            $this-> {
                $name
            }
            = $value;
        }
    }
}

接下来创建一个新的 Account 对象,并调用新的 loadFromJSON 函数

调用 loadFromJSON 函数来将账户的 JSON 反序列化为 Account 对象;最后一行会输出 “Bob Barker”

$json = json_encode($account);

$deserializedAccount = new Account();
$deserializedAccount->loadFromJSON($json);

echo $deserializedAccount->firstName . " " . $deserializedAccount-> lastName;

3. 请求JSON

使用 PHP 内置的 file_get_contents 函数来创建 HTTP 请求。该函数会将资源以字符串的形式返回。然后就可以将字符串反序列化为 PHP 对象

本地 CouchDB API 在 http://localhost:5984/accounts/ddc14efcf- 71396463f53c0f8800019ea 响应的资源

{
    "_id": "ddc14efcf71396463f53c0f8800019ea",
    "_rev": "6-69fd853972074668f99b88a86aa6a083",
    "address": {
        "street": "123 fakey ln",
        "city": "Some Place",
        "state": "CA",
        "zip": "96037"
    },
    "gender": "female",
    "famous": false,
    "age": 28,
    "firstName": "Mary",
    "lastName": "Thomas"
}

调用内置的 file_get_contents 函数请求上例中的 JSON 资源。 然后创建一个新的 Account 对象,并调用 loadFromJSON 进行反 序列化操作。最后一行将输出 “Mary Thomas”

$url = "http://localhost:5984/accounts/3636fa3c716f9dd4f7407bd6f700076c";
$json = file_get_contents($url);

$deserializedAccount = new Account();
$deserializedAccount->loadFromJSON($json);

echo $deserializedAccount->firstName . " " . $deserializedAccount-> lastName;

9.2 发送JSON HTTP请求的其他方式

接下来看看服务端上一些请求 JSON 的小例子。在每个小例子中,都能看 到使用 HTTP 请求 JSON 资源,将资源解析为对象,以及 JSON 文档中的值 的渲染。

下面所有示例使用的 JSON 文档都来源于 OpenWeatherMap API。渲染的值都基于 http://api.openweathermap.org/data/2.5/weather?q=London,uk这 一 JSON 文档的子集

OpenWeatherMap API 中 JSON 资源的坐标对象,其值代表伦 敦的经纬度

{
    "coord": {
        "lon": -0.13,
        "lat": 51.51
    }
}

9.2.1 Ruby on Rails

Ruby on Rails 是一个服务端的 Web 应用框架。它使用 Ruby 语言编写且基 于模型 - 视图 - 控制器(MVC)架构。

我们需要 JSON ruby gem。一旦装好了 JSON ruby gem,解析 JSON 就变得很简单了,只需执行 JSON.parse()

向 OpenWeatherMap API 发送请求,并将 JSON 反序列化

为 Ruby 对象。借助代码的最后一行,我们在页面中渲染出了数据中坐标 (coord)对象中的经度值(lon)。

向 OpenWeatherMap API 发送请求

require 'net/http'
require 'json'

url = URI.parse('http://api.openweathermap.org/data/2.5/ weather?q=London,uk')
request = Net::HTTP::Get.new(url.to_s)
response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)
}

weatherData = JSON.parse(response.body) 
render text: weatherData["coord"]["lon"]

9.2.2 Node.js

Node.js 是服务端的 JavaScript(脱离了浏览器),它基于谷歌的开源JavaScript 引擎 V8。有了 Node.js,就可以使用 JavaScript 编写服务端应用。

前面的章节探讨过 JSON 与客户端的 JavaScript,并通过 JSON.parse() 轻松 地将 JSON 反序列化为 JavaScript 对象。因为 Node.js 也是 JavaScript,所以 方法都是一样的。

不过,在 Node.js 中不再使用 XMLHttpRequest 对象,因为该对象是仅在互联 网浏览器中使用的 JavaScript 对象。在 Node.js 中,通过更简单的 get() 函 数来请求 JSON(以及其他类型的资源)。

示例中,向 OpenWeatherMap API 发送请求,并将得到的 JSON 反序 列化为 JavaScript 对象。然后通过 console.log() 输出坐标(coord)对象中的经度值(lon)。

向 API 发送 HTTP 请求并将其反序列化为 JavaScript 对象

var http = require('http'); http.get({
    host: 'api.openweathermap.org',
    path: '/data/2.5/weather?q=London,uk'
}, function (response) {
    var body = '';
    response.on('data', function (data) {
        body += data;
    });
    response.on('end', function () {
        var weatherData = JSON.parse(body); console.log(weatherData.coord.lon);
    });
});

9.2.3 Java

Java 是一种面向对象的编程语言。Java 中的许多库都提供了对 JSON 的支持。在这一部分中,我将使用下面 的库来通过 URL 获取 JSON,并将其序列化为 Java 对象。

  • Apache Commons IO
  • JSON in Java

示例中,从 OpenWeatherMap API 中以字符串的形式获取 JSON 资源。 然后通过实例化 JSONObject 将 JSON 字符串反序列化。最后使用 System. out.println() 输出坐标(coord)对象中的经度值(lon)。

通过 JSONObject 反序列化 JSON 字符串

import org.apache.commons.io.IOUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URL;


public class HelloWorldApp {
    public static void main(String[] args) throws IOException, JSONException {
        String url = "http://api.openweathermap.org/data/2.5/ weather?q=London,uk";
        String json = IOUtils.toString(new URL(url));
        JSONObject weatherData = new JSONObject(json);
        JSONObject coordinates = weatherData.getJSONObject("coord");
        System.out.println(coordinates.get("lon"));
    }
}

第10章 总结

JSON用途并没有局限于某一个方 面。我们知道它在NoSQL 中是存储数据的载体。而且,JSON 也在逐渐成 为项目中有用的工具。

为了进一步说明,让我们最后来看看 JSON 的另一 用途: 作为配置文件放在某一个地方。

10.1 作为配置文件的JSON

由于JSON具备广泛的支持、服务端解析的便利性以及良好的可读性,JSON 常用来存储配置信息。

来比较一下使用 INI、XML、JSON 三种格式存储同样设置的区别

使用 INI 格式的某游戏配置文件(settings.ini)

[general] 
playIntro=false 
mouseSensitivity=0.54

[display] 
complexTextures=true 
brightness=4.2 
widgetsPerFrame=326 
mode=windowed

[sound]
volume=1 
effects=0.68

用 XML 格式的某游戏配置文件(settings.xml)

<?xml version="1.0" encoding="utf-8"?>
<settings>
    <general>
        <playIntro>false</playIntro>
        <mouseSensitivity>0.54</mouseSensitivity>
    </general>
    <display>
        <complexTextures>true</complexTextures>
        <brightness>4.2</brightness>
        <widgetsPerFrame>326</widgetsPerFrame>
    </display>
    <sound>
        <volume>1</volume>
        <effects>0.68</effects>
    </sound>
</settings>

使用 JSON 格式的某游戏配置文件(settings.json)

{
    "general": {
        "playIntro": false, 
        "mouseSensitivity": 0.54
    }, 
    "display": {
        "complexTextures": true, 
        "brightness": 4.2, 
        "widgetsPerFrame": 326, 
        "mode": "windowed"
    }, 
    "sound": {
        "volume": 1, 
        "effects": 0.68
    }
}

这三种格式都有着良好的可读性,而且修改起来也很方便。

每种格式都有优点和缺点。

INI 格式没有 XML 那些大于号和小于号以及 JSON 的花括号,所以有更好的可读性。不过 INI 格式不能很好地表示更为复杂的信息,如嵌套信息或复杂的列表。

XML够包含更为复杂的数据, 但是它像 JSON 一样具有数据类型

除了这些数据格式本身具有的优缺点外,是否能够很方便地被编程语言 / 框架解析也是一个很重要的考量因素。如果 JSON 解析器已经在你的应用中 深度使用了,那么 JSON 可能是你配置文件的最佳选择。

现实中一个使用 JSON 作 为配置文件的极佳例子就是 Node.js 默认的 JavaScript 包管理器:npm。当 然,它也被 AngularJS 和 jQuery 等其他框架使用。

npm 包管理器使用 JSON 作为配置文件,文件名称为 package.json。该文件 包含了每个包的具体信息,如名称、版本、作者、贡献者、依赖、脚本以 及许可:

npm 的 package.json 示例文件

{
    "name": "bobatron", 
    "version": "1.0.0", 
    "description": "The extraordinary library of Bob.", 
    "main": "bob.js", 
    "scripts": {
        "prepublish": "coffee -o lib/ -c src/bob.coffee"
    }, 
    "repository": {
        "type": "git", 
        "url": "git://github.com/bobatron/bob.git"
    }, 
    "keywords": [
        "bob", 
        "tron"
    ], 
    "author": "Bob Barker <bob.barker@fakemail.com> (http://bob.com/)", 
    "license": "BSD-3-Clause", 
    "bugs": {
        "url": "https://github.com/bobatron/issues"
    }
}

尽管 JSON 是作为配置文件放在一个地方的,但从某种意义上讲,它还是 在扮演着数据交换格式的角色。对于存放在某处的配置文件来说,交换仍在人和计算机之间进行着,而数据则在其中起着沟通作用。

10.2 结语

无论是作为服务器上的配置文件,还是作为通过 URL 请求的资源,JSON 始终都在履行作为数据交换格式的职责。本书中,我们一步步探索了这些职责(或是角色)。让我们最后概括一下 JSON 是如何在我们的生活中发挥作用的。

在服务端,对象可以被序列化为 JSON 格式的文本,并且通过反序列化 变回对象。服务端代码可以请求 JSON。在第 9 章中,我们了解了如何用 ASP.NET 和 PHP 去实现这一功能。

此外,JSON 也可以被看作一种文本格式,用作一种面向文档存储类型的数 据库的文档。第 8 章介绍了使用此方法的 CouchDB。该数据库同时提供了 可用于 HTTP Web API 的接口。

HTTP Web API 是一个对诸如 HTML 或 JSON 文档等资源进行请求和 响应的系统。这些文档使用 URL 经由 HTTP 请求。第 6 章就讲解了 OpenWeatherMap API 是如何利用这一点以 JSON 资源的形式提供天气数 据的。

JavaScript XmlHttpRequest 可 以 通 过 URL 请 求 JSON 资 源。 为 了 在 JavaScript 代码中使用 JSON,要先将它反序列化为 JSON 对象。JavaScript内置的 JSON.parse() 函数能够快速而有效地实现这一功能。

从 JavaScript 对象到 JSON,再到服务端的对象,能够看到数据跑了一圈。 每一天,数据都在全世界各种系统中进进出出,它们的载体就是数据交换格式

我们再次从高空俯瞰,可以发现 JSON 并不是唯一一种数据交换格式。有 些数据以逗号分隔值(CSV)为载体,还有些是 Excel 表格。它们都是表格 化的。还有些数据以 XML 格式存在,这种格式支持数据的嵌套。

数据有多种格式与形式。有多种不同的系统在不停地推送和接收着数据。 在考虑使用什么数据交换格式时,数据的形式和交换数据的系统都应该被 考虑到。虽说本书青睐于 JSON,并对它进行了全方位的介绍,但要记住, JSON 不总是最佳选择

在互联网浏览器这类通过 JavaScript 来支持面向对象编程的系统中,JSON 是较为理想的数据交换格式。在使用 JavaScript 与 Web API 交流或是创建 AJAX 交互时,JSON 都有极佳的表现。

对于那些诸如面向对象的服务端 Web 框架之类的系统,JSON 依旧是理想 的数据交换格式。有了 JSON,数据就可以以对象字面量的形式在系统中进 出,并保持它原有的结构。

就像本章 10.1 节“作为配置文件的 JSON”所提到的例子那样,选择格式 前应先考虑优缺点。用对的工具,去做对的工作。

小结

第一次尝试将一本书籍内容的概要摘选出来写博文,这样再摘选的过程中相当于是阅读书籍了,国光这样尝试了一下,发现阅读效率还是很高的,一本书可以很快阅读完。所以我又开了一个Books书籍分类的目录,博客日后会大量更新相关书籍的摘要文章。


文章作者: 国光
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 国光 !
自从点了 👇 广告,腰也不酸了,腿也不疼了
点一下 👆 玩一年 装备不花一分钱!
 上一篇
AWVS13.X破解版 Windows、Linux、Docker AWVS13.X破解版 Windows、Linux、Docker
Acunetix Web Vulnerability Scanner(AWVS)经典商业漏扫工具,最近更新了13的版本,本文分享的AWVS的破解版是网上大佬们分享出来的国光我只是一个小小搬运工。折腾AWVS的原因是正好最近准备用Django
2020-04-12
下一篇 
使用Django重写我的Hexo博客 使用Django重写我的Hexo博客
Django学的差不多了是时候展现真正的技术了!于是乎就拿我的博客开刀做实验,前端保持不变,用Django来重写后端,话不多说,下面就开始我的装逼了… 开发环境项目地址:https://github.com/sqlsec/Django-
2020-03-10
  目录