本页介绍了如何实现支持图表工具数据源协议的服务,以使用 Query 类向图表公开数据。
内容
观众
本页面主要面向将在没有 Chart Tools 数据源库帮助下创建自己的数据源的开发者。 如果您使用该库或任何其他帮助程序库,请先阅读该库的文档。
本页面还适用于有兴趣了解用于在客户端可视化与数据源之间进行通信的有线协议的读者。
如果您要创建或使用可视化图表,则无需阅读本页面。
为了阅读本文档,您应该了解基本的 JSON 和 HTTP 请求语法。您还应该从用户的角度了解图表的工作原理。
概览
您可以实现 Chart Tools Datasource 协议,以便成为您自己的图表或其他图表的数据源提供程序。图表工具数据源提供一个网址(称为数据源网址),图表可以向该网址发送 HTTP GET 请求。作为响应,数据源会返回格式正确的数据,图表可以使用这些数据在网页上呈现图形。这种请求-响应协议称为 Google 可视化 API 传输协议。
数据源提供的数据可以从各种资源(如文件或数据库)中提取。唯一的限制是,您可以将数据格式设置为包含类型化列的二维表格。
作为 Chart Tools 数据源,您必须以特定格式解析请求,并以特定格式返回响应。您可以通过以下两种常规方式之一来执行此操作:
-
使用下列帮助程序库来处理请求和响应,并构造要返回的 DataTable。如果您使用了其中一个库,只需编写代码,即可以表格的形式将数据提供给库。
- Java 数据源库 - 处理请求和响应,根据您提供的数据创建响应表,并实现 Google 图表工具 SQL 查询语言。
- Python 数据源库 - 用于创建响应表以生成响应语法。不负责解析请求或实现 Google 图表工具 SQL 查询语言。
或
- 通过处理请求、构建 DataTable 并发送响应,从头开始编写您自己的数据源。
运作方式:
- 数据源公开了一个网址(称为数据源网址),图表会向该网址发送 HTTP GET 请求。
- 客户端发出 HTTP GET 请求,其中包含描述返回数据所用格式的参数、可选查询字符串和可选自定义参数。
- 数据源会接收并解析请求,如请求格式中所述。
- 数据源会按照请求的格式准备数据;通常,这是一个 JSON 表。如需了解响应格式,请参阅响应格式部分。Datasource 可以选择支持可视化 API 查询语言,该语言用于指定过滤、排序和其他数据操作。
- 数据源会创建一个包含序列化数据和其他响应参数的 HTTP 响应,并将其发送回客户端,如响应格式中所述
注意:对于请求和响应,本文档中列出的所有参数和字符串常量值(例如 responseHandler
和“ok”)都小写且区分大小写。
最低要求
以下是使用图表工具数据源的最低要求:
- 数据源应该接受 HTTP GET 请求,并且应可供您的客户端使用。
- 该协议可以更改并支持版本方案(当前版本为 0.6),因此您的数据源应支持使用先前版本以及当前版本的请求。您应在新版本推出后立即提供支持,以免任何客户端快速升级到最新版本。
- 如果请求中发送了未知属性,请勿失败。这是因为新版本可能会引入您不知道的新属性。
- 仅解析您预期的属性。虽然新版本可能会引入新属性,但不要盲目接受和使用整个请求字符串。 为防范恶意攻击,请仔细解析并仅使用您预期的属性。
- 如果您没有自行编写客户端图表,请仔细记录数据源要求。这包括记录以下信息:
- 您接受的所有自定义参数
- 您能否解析 Google 可视化 API 查询语言,以及
- 您要返回哪类数据,以及这些数据的结构(行和列代表什么,以及任何标签)。
- 对接受来自未知客户端的请求的网站采取所有标准安全预防措施。您可以合理地在参数中支持 MD5、哈希和其他安全机制,以便对请求进行身份验证或帮助防范恶意攻击,并期望客户端了解您的要求并做出响应。但是,如果您未自行编写图表,请务必妥善记录所有要求。请参阅下面的安全注意事项。
- 所有请求和响应字符串都应采用 UTF-8 编码。
- 最重要的响应格式是 JSON。请务必先实现 JSON,因为这是大多数图表使用的格式。然后添加其他响应类型。
- 您不要求支持可视化 API 查询语言,但这会使您的数据源对客户更有用。
- 您不需要支持来自任何和所有图表类型的请求,并且可以为自定义图表支持自定义参数。但是,您应该以下述标准格式返回响应。
安全注意事项
在设计数据源时,您需要考虑数据的安全性。您可以为网站采用各种安全机制,从简单的密码访问到安全的 Cookie 身份验证,不一而足。
图表会带来 XSSI(跨站脚本包含)攻击。 用户可能会转到包含恶意脚本的网页,然后尝试使用当前用户的凭据查询数据源网址。如果用户尚未退出网站,脚本将作为当前用户进行身份验证,并且拥有该网站上的权限。与 JSONP 类似,恶意脚本可以使用 <script src> 标记来包含数据源。
为了提高安全性,您可以考虑将请求限制为来自与数据源相同的网域的请求。这会极大地限制数据源的可见性,但如果您的某些敏感数据不应从网域外部访问,则应予以考虑。仅允许来自同一网域的请求的数据源称为“受限数据源”,而“不受限制的数据源”将接受来自任何网域的查询。以下是有关如何实现受限数据源的一些详细信息:
如需确保请求确实来自您的网域内,而非来自外部网域(或网域内的 XSRF 攻击下的浏览器),请执行以下操作:
- 验证请求中是否存在“X-DataSource-Auth”标头。此标头由 Google 可视化 API 定义;您无需检查此标头的内容,只需对其进行验证即可。如果您使用的是 Google 图表工具数据源库,则可以让该库为您处理此问题。
- 使用 Cookie 身份验证对客户端进行身份验证。没有办法将自定义标头注入到跨网域请求,同时仍能保留身份验证 Cookie。
- 让 JavaScript 添加到 <script src> 代码中时不太可能执行。为此,请在您的 JSON 响应中添加 )]}' 前缀,后跟换行符。在客户端中,从响应中移除前缀。对于 XmlHttpRequest,只有当请求来自同一个网域时,才能这样做。
请求格式
客户端发送包含多个参数的 HTTP GET 请求,这些参数包括自定义元素、可选查询字符串、签名和其他元素。您只负责解析本节中所述的参数,并且应注意不要处理他人以避免受到恶意攻击。
请务必为可选参数(标准和自定义)提供默认值,并在网站文档中记录所有默认值。
以下是几个示例请求(您可以在本文档末尾的示例中看到更多请求和响应示例):
注意:应在请求之前对以下请求字符串以及示例部分中显示的请求字符串进行网址转义。
Basic request, no parameters: http://www.example.com/mydatasource Request with the tqx parameter that contains two properties: http://www.example.com/mydatasource?tqx=reqId:0;sig:4641982796834063168 Request with a query string: http://www.example.com/mydatasource?tq=limit 1
以下是请求字符串中所有标准参数的列表。请注意,参数名称(例如“version”)和常量字符串值(例如“ok”、“warning”和“not_modify”)均区分大小写。该表格还会说明是否需要发送参数,以及发送参数时是否需要处理此参数。
参数 | 在请求中必须提供? |
数据源必须处理? |
说明 |
---|---|---|---|
TQ | 否 |
否 |
使用 Google 可视化图表 API 查询语言编写的查询,用于指定如何过滤、排序或以其他方式控制返回的数据。该字符串不需要加引号。 示例: |
TQX | 否 |
是 |
一组以英文冒号分隔的键值对,它们适用于标准参数或自定义参数。各个键值对之间用英文分号分隔。下面列出了可视化图表协议定义的标准参数:
示例: |
tqrt | 否 |
否 |
预留:忽略此参数。用于发送查询的方法。 |
响应格式
响应的格式取决于请求的 out
参数,该参数用于指定预期的响应类型。请参阅以下部分,了解如何响应每种请求类型:
- JSON - 返回的 JSON 响应中包含 JavaScript 对象中的数据,这些数据可以直接传递给
DataTable
构造函数进行填充。这是迄今为止最常见的请求类型,也是正确实现的最重要要求。 - CSV - 返回以英文逗号分隔的平面值列表,以便浏览器进行处理。
- TSV - 返回由制表符分隔的值列表,该列表将由浏览器处理。
- HTML - 返回浏览器要呈现的 HTML 表格。
您可以使用 Google 可视化数据源库 (java) 或可视化 Python 库为您生成这些输出格式。
JSON 响应格式
如果请求包含“X-DataSource-Auth”标头,则默认响应格式为 JSON,否则为 JSONP。请注意,Google 图表客户端实际上支持经过修改的 JSON 和 JSONP 版本;如果您使用的是 Java 或 Python 帮助程序库,这些库将为您放置适当的代码;如果您要手动解析响应,请参阅下文的 JSON 修改。
如果您强制执行同一网域请求,则应验证请求中是否存在“X-DataSource-Auth”标头,并使用授权 Cookie。
这是 Google 可视化 API 方法 google.visualization.Query.send()
指定的唯一响应格式。您可以在本页面末尾的示例中看到一些 JSON 请求和响应示例。您可以使用 Java 或 Python 帮助程序库为您创建此响应字符串。
此响应格式是一个 UTF-8 编码的 JSON 对象(由大括号 { } 封装的对象,各个属性用英文逗号隔开),其中包含下表中的属性(数据已分配给 table
属性)。此 JSON 对象应封装在请求的 responseHandler
参数值中。因此,如果请求的 responseHandler
值为“myHandler”,就应返回如下所示的字符串(为简单起见,仅显示一个属性):
"myHandler({status:ok, ...})"
如果请求不包含 responseHandler
值,则默认值为“google.visualization.Query.setResponse”,因此您应返回如下所示的字符串(为简单起见,系统只显示一个属性):
"google.visualization.Query.setResponse({status:ok, ...})"
以下是可用的响应对象成员:
属性 | 是否必需? |
说明 |
---|---|---|
version | 否 |
表示 Google 可视化传输协议版本号的字符串编号。如果未指定,客户端将采用最新版本。 示例: |
要求 ID | 是* |
一个字符串数字,表示针对此客户端的此请求的 ID。如果请求中包含此参数,则返回相同的值。如需了解详情,请参阅请求部分中的 reqId 说明。*如果请求中未指定此参数,则无需在响应中设置。 |
status | 是 |
描述此操作成功或失败的字符串。只能是以下值之一:
示例: |
警告 | 仅当 status=warning 时 |
一个或多个对象的数组,其中每个对象都描述了一个非严重问题。如果
示例: |
错误 | 如果 status=error ,则为必需 |
包含一个或多个对象的数组,其中每个对象都描述了一个错误。如果 该数组具有以下字符串成员(仅为每个成员返回一个值):
示例: |
签名 | 否 |
表对象的哈希值。可用于优化客户端与数据源之间的数据传输。您可以选择任何哈希算法。 如果您支持此属性,则应在没有返回任何数据的情况下返回客户端传入的值;如果返回了新数据,则应返回新的哈希值。 示例: |
表 | 否 |
JavaScript 字面量表示法中的 {cols:[{id:'Col1',label:'',type:'number'}], rows:[{c:[{v:1.0,f:'1'}]}, {c:[{v:2.0,f:'2'}]}, {c:[{v:3.0,f:'3'}]}, {c:[{v:1.0,f:'1'}]} ] } 仅当 示例:请参阅下文的示例。 |
Google 的辅助程序库以及发送到 Google 的所有查询都会返回严格的 JSON/JSONP。
如果您没有自行解析返回的代码,这应该无关紧要。如果是,您可以使用 JSON.parse() 将 JSON 字符串转换为 JavaScript 对象。API 处理 JSON 的方式有一个不同之处,虽然 JSON 不支持 JavaScript 日期值(例如,“new Date(2008,1,28,0,31,26));但 API 支持以字符串形式表示的有效日期(采用 JSON 格式,格式如下:Date(year, month, day[,hour, minute, second[, millisecond]])
,其中“日期”后面的所有内容都是可选的,月份从零开始)。
优化 JSON 响应
如果客户端发出了两个请求,并且数据在各个请求之间未发生变化,那么请勿重新发送数据;这样做会浪费带宽。为了提高请求效率,该协议支持在客户端上缓存数据,并在自上次请求以来数据未更改的情况下在响应中发送信号。具体算法如下:
- 客户端向数据源发送请求。
- 数据源生成
DataTable
以及DataTable
对象的哈希值,并在其响应中返回二者(哈希值在tqx.
sig
参数中返回)。Google 可视化 API 客户端会缓存DataTable
和sig
值。 - 客户端再次发送数据请求,包括缓存的
tqx.sig
值。 - 数据源可以通过以下两种方式之一来响应:
- 如果数据从上一个请求中发生更改,数据源会发回新的
DataTable
和新的sig
值哈希值。 - 如果数据与上一个请求相比没有变化,数据源就会发回
status=error
、reason=not_modified
、sig=old_sig_value
。
- 如果数据从上一个请求中发生更改,数据源会发回新的
- 无论是哪种情况,托管该图表的页面都会获得成功响应,并且可以通过调用
QueryResponse.getDataTable()
来检索DataTable
。如果数据相同,则它只是该表格的缓存版本。
请注意,这仅适用于基于 Google 可视化 API 构建的图表中的 JSON 请求。
CSV 响应格式
如果请求指定 out:csv
,则响应不包含任何元数据,而只是数据的 CSV 表示形式。CSV 表通常是一个逗号分隔列表,其中每行数据都是以英文逗号分隔的值列表,以 UNIX 换行符 (\n) 结尾。每一列的单元格值都应具有相同的类型。第一行是列标签。下面是一个三行三列的表格示例:
A, B, C 1.0, "yes", true 2.0, "no", false 3.0, "maybe", true
此协议未指定 CSV 格式;数据源负责定义其 CSV 格式。不过,一种常见格式是一组值,以英文逗号分隔各个值(中间没有空格),每行的末尾都有一个换行符 (\n)。当浏览器收到 CSV 字符串回复时,可能会询问用户要使用哪个应用打开字符串,或者直接在屏幕上渲染该字符串。Java 和 Python 开源库提供了一种将 DataTable 转换为 CSV 字符串的方法。
如果请求包含 tqx
参数的 outFileName
成员,您应尝试在响应标头中包含指定的文件名。
google.visualization.Query
对象不支持请求 CSV 响应。如果客户端想要请求 CSV,您可以在网页上嵌入可视化工具栏小工具,或者他们可以使用自定义代码创建请求,或者您可以提供明确设置 tqx
的 out:csv
属性的链接,如以下请求网址中所示:
请求
http://www.example.com/mydatasource?tqx=reqId:1;out:csv
响应
Label 1,Label2\n1,a\n2,b\n3,c\n4,d
TSV 响应格式
如果请求指定 out:tsv-excel
,则响应不包含任何元数据,而只是以制表符分隔的数据(采用 utf-16 编码)表示。如果请求包含 tqx
参数的 outFileName
成员,您应尝试在响应标头中包含指定的文件名。
HTML 响应格式
如果请求指定 out:html
,则响应应该是定义包含数据的 HTML 表格的 HTML 页面。这对于调试代码很有用,因为浏览器可以直接以可读格式呈现结果。您无法使用 google.visualization.Query
对象发送 HTML 响应查询。您必须使用自定义代码或在浏览器中输入类似下面的网址来查询 HTML 响应:
请求
http://www.example.com/mydatasource?tqx=reqId:1;out:html
响应
<html><body><table border='1' cellpadding='2' cellspacing='0'><tr style='font-weight: bold; background-color: #aaa;'><td>label 1</td><td>label 2</td></tr><tr bgcolor='#f0f0f0'><td align='right'>1</td><td>a</td></tr><tr bgcolor='#ffffff'><td align='right'>2</td><td>b</td></tr><tr bgcolor='#f0f0f0'><td align='right'>3</td><td>c</td></tr><tr bgcolor='#ffffff'><td align='right'>4</td><td>d</td></tr></table></body></html>
示例
以下是一些请求和响应示例。请注意,请求未进行网址转义;这通常是由浏览器或 google.visualization.Query
对象完成的。
简单请求:返回基本信息,其中包含三列四行的表。
Request: http://www.example.com/mydatasource Response google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'ok',sig:'5982206968295329967',table:{cols:[{id:'Col1',label:'',type:'number'},{id:'Col2',label:'',type:'number'},{id:'Col3',label:'',type:'number'}],rows:[{c:[{v:1.0,f:'1'},{v:2.0,f:'2'},{v:3.0,f:'3'}]},{c:[{v:2.0,f:'2'},{v:3.0,f:'3'},{v:4.0,f:'4'}]},{c:[{v:3.0,f:'3'},{v:4.0,f:'4'},{v:5.0,f:'5'}]},{c:[{v:1.0,f:'1'},{v:2.0,f:'2'},{v:3.0,f:'3'}]}]}});
包含响应处理程序的简单请求:返回一个包含三列三行的表,该表具有不同的数据类型。
Request: http://www.example.com/mydatasource?tqx=responseHandler:myHandlerFunction Response myHandlerFunction({version:'0.6',reqId:'0',status:'ok',sig:'4641982796834063168',table:{cols:[{id:'A',label:'NEW A',type:'string'},{id:'B',label:'B-label',type:'number'},{id:'C',label:'C-label',type:'datetime'}],rows:[{c:[{v:'a'},{v:1.0,f:'1'},{v:new Date(2008,1,28,0,31,26),f:'2/28/08 12:31 AM'}]},{c:[{v:'b'},{v:2.0,f:'2'},{v:new Date(2008,2,30,0,31,26),f:'3/30/08 12:31 AM'}]},{c:[{v:'c'},{v:3.0,f:'3'},{v:new Date(2008,3,30,0,31,26),f:'4/30/08 12:31 AM'}]}]}});
使用简单的查询字符串进行查询:如果请求使用单个列,则返回包含四行内容的单个列。
Request: http://www.example.com/mydatasource?tq=select Col1 Response: google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'ok',sig:'6099996038638149313',table:{cols:[{id:'Col1',label:'',type:'number'}],rows:[{c:[{v:1.0,f:'1'}]},{c:[{v:2.0,f:'2'}]},{c:[{v:3.0,f:'3'}]},{c:[{v:1.0,f:'1'}]}]}});
数据未修改错误:not_modified
错误的示例。
Request: http://www.example.com/mydatasource?tqx=reqId:0;sig:4641982796834063168 Response: google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});
数据被截断的警告:data_truncated
警告的示例。
请注意,请求仍会返回数据。
Request: http://www.example.com/mydatasource?tq=limit 1 Response: google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'warning',warnings:[{reason:'data_truncated',message:'Retrieved data was truncated'}],sig:'1928724788649668508',table:{cols:[{id:'A',label:'NEW A',type:'string'},{id:'B',label:'B-label',type:'number'},{id:'C',label:'C-label',type:'datetime'}],rows:[{c:[{v:'a'},{v:1.0,f:'1'},{v:new Date(2008,1,28,0,31,26),f:'2/28/08 12:31 AM'}]}]}});
访问遭拒错误:access_denied
错误的示例。
Request: http://www.example.com/mydatasource Response: google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'error',errors:[{reason:'access_denied',message:'Access denied',detailed_message:'Access Denied'}]});
无效的查询字符串:包含无效查询字符串的请求示例。请注意,详细消息是通用消息,而不是实际错误消息。
Request: http://www.example.com/mydatasource?tq=select A Response: google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'error',errors:[{reason:'invalid_query',message:'Invalid query',detailed_message:'Bad query string.'}]});
开发工具
- Java Datasource 库(由 Google 提供) - 处理请求和响应,根据您提供的数据创建响应表,并实现 Google 图表工具 SQL 查询语言。
- Python Datasource 库(来自 Google)- 创建响应表以生成响应语法。不负责解析请求或实现 Google 图表工具 SQL 查询语言。
- MC-Google_Visualization(第三方)- 这是一个 PHP 服务器端库,您可以使用 PDO 为 MySQL、SQLite 和 PostgreSQL 数据库引擎实现图表工具数据源。
- bortosky-google-visualization(第三方)- 这是一个辅助库,用于为 .NET 用户创建 Google 可视化 API 数据表。
- GV 视频流(第三方)- GV 视频流是一种服务器端工具,可以将不同来源的数据转换为对 Google 图表的有效查询响应。GV Streamer 支持多种语言(例如 PHP、Java、.NET)和几种原始数据源(例如 MySql)。
- TracGViz(第三方)- TracGViz 是一款免费的开源工具,可提供各种组件,以便 Trac 能够使用图表小工具,以及实现由 Trac 管理的数据作为 Google 图表工具数据源。
- vis-table(第三方)- 在 PHP 中实现 Google 图表工具数据源的库。它主要包含三个部分。数据表实现本身、查询语言解析器和格式化程序。
- Oracle PL/SQL 中的 Google 数据源实现(第三方)- 一个 Oracle PL/SQL 软件包,可让 Oracle 直接从数据库提供数据源。因此,基本上您可以将任何 Oracle 查询用作 Google 图表工具数据源(软件包将返回包含数据的 JSON 文件)。它几乎全面支持 Google 查询语言。