本页面介绍了如何实现支持图表工具数据源协议的服务,以便使用 Query 类向图表公开数据。
目录
观众
本页面主要面向将不借助图表工具数据源库创建自己的数据源的开发者。 如果您使用的是该库或任何其他帮助程序库,请先阅读该库的文档。
本页面还面向有兴趣了解在客户端可视化图表与数据源之间进行通信所用的传输协议的读者。
如果您要创建或使用可视化图表,则无需阅读本页内容。
为了阅读本文档,您应该了解基本的 JSON 和 HTTP 请求语法。您还应该从用户的角度了解图表的工作方式。
概览
您可以实现图表工具数据源协议,以便成为您自己的图表或其他图表的数据源提供商。图表工具数据源会公开一个称为数据源网址的网址,图表可以将 HTTP GET 请求发送到该网址。作为响应,数据源会返回格式正确的数据,图表可以使用这些数据在网页上渲染图形。这种请求-响应协议称为 Google Visualization API 有线协议。
数据源提供的数据可以从各种资源(例如文件或数据库)中提取。唯一的限制是,您可以将数据的格式设置为包含类型化列的二维表。
作为图表工具数据源,您必须解析特定格式的请求,并返回特定格式的响应。您可以通过以下两种常见方式之一执行此操作:
-
使用以下某个帮助程序库处理请求和响应,并构造要返回的 DataTable。如果您使用其中某个库,只需编写将数据以表的形式提供给库所需的代码。
- Java 数据源库 - 处理请求和响应,根据您提供的数据创建响应表,并实现 Google 图表工具 SQL 查询语言。
-
Python 数据源库 - 创建一个生成响应语法的响应表。不负责解析请求或实现 Google 图表工具 SQL 查询语言。
或
- 通过处理请求、构建 DataTable 和发送响应,从头开始编写您自己的数据源。
运作方式:
- 数据源会公开一个网址(称为数据源网址),图表会向该网址发送 HTTP GET 请求。
- 客户端会发出 HTTP GET 请求,其中包含用于说明所返回数据所用格式的参数、可选的查询字符串和可选的自定义参数。
- 数据源会接收并解析请求,如 请求格式中所述。
- 数据源按照请求的格式准备数据;通常是 JSON 表。响应格式部分介绍了响应格式。数据源可以选择性地支持指定过滤、排序和其他数据操作的可视化 API 查询语言。
- 数据源会创建一个包含序列化数据和其他响应参数的 HTTP 响应,然后按照响应格式中的说明将其发送回客户端。
注意:本文档中列出的请求和响应的所有参数和字符串常量值(例如 responseHandler
和“ok”)均小写且区分大小写。
最低要求
要充当图表工具数据源,必须满足以下最低要求:
- 该数据源应接受 HTTP GET 请求,并可供客户端使用。
- 协议可能会发生变化并支持版本方案(当前版本为 0.6),因此您的数据源应支持使用先前版本和当前版本的请求。您应该尝试在新版本发布后对其进行支持,以避免中断任何快速升级到最新版本的客户端。
- 如果未知属性在请求中发送,不会失败。这是因为新版本可能会引入您不知道的新属性。
- 仅解析预期的属性。尽管新版本可能会引入新属性,但请勿盲目接受并使用整个请求字符串。为了保护自己免遭恶意攻击,请仔细解析并仅使用预期的属性。
- 如果您不是自行编写客户端图表编码,请仔细记录您的数据源要求。这包括记录以下信息:
- 接受的所有自定义参数
- 您能否解析 Google Visualization API 查询语言,以及
- 返回的数据类型以及数据的结构(行和列所代表的内容以及任何标签)。
- 针对接受来自未知客户端的请求的网站采取所有标准安全预防措施。您可以在参数中合理支持 MD5、哈希和其他安全机制,以对请求进行身份验证或帮助防范恶意攻击,同时希望客户端了解您的要求并做出响应。但是,如果您没有自行编写图表代码,请务必妥善记录您的所有要求。请参阅下面的安全注意事项。
- 所有请求和响应字符串都应采用 UTF-8 编码。
- 最重要的响应格式是 JSON。请务必先实现 JSON,因为这是大多数图表使用的格式。然后添加其他响应类型。
- 您不要求支持 Visualization API 查询语言,但这样做可让您的数据源对客户更有用。
- 您不必支持来自任何或所有图表类型的请求,但可以支持自定义图表的自定义参数。但您应该以下述标准格式返回响应。
安全注意事项
设计数据源时,您需要考虑数据必须有多安全。您的网站可以采用多种安全方案,从简单的密码访问到安全的 Cookie 身份验证,不一而足。
XSSI(跨站脚本包含)攻击是图表的风险。用户可能会前往包含恶意脚本的网页,然后该脚本开始尝试使用当前用户的凭据对数据源网址进行查询。如果用户尚未退出某个网站,则该脚本将作为当前用户进行身份验证,并且对该网站拥有权限。使用 <script src> 标记,与 JSONP 类似,恶意脚本能够包含数据源。
为进一步提高安全性,您可以考虑将请求限制为来自与您的数据源位于同一网域。这会极大地限制数据源的可见性,但如果您的网域非常敏感且不可从网域外部访问,就应考虑这样做。仅允许来自同一网域的请求的数据源称为“受限数据源”,与之相对的“不受限数据源”会接受来自任何网域的查询。以下是有关如何实现受限数据源的一些详细信息:
如需确保请求确实来自您的网域内部,而不是来自外部网域(或受到 XSRF 攻击的网域内的浏览器),请执行以下操作:
- 验证请求中是否存在“X-DataSource-Auth”标头。 此标头由 Google Visualization 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_modified”)都区分大小写。该表还说明了是否需要发送该参数;如果已发送,则还说明了您是否需要处理该参数。
参数 | 请求中必填吗? |
数据源必须处理? |
说明 |
---|---|---|---|
TQ | 否 |
否 |
使用 Google Visualization API 查询语言编写的查询,用于指定如何对返回的数据进行过滤、排序或以其他方式处理。该字符串不需要加引号。 示例: |
TQX | 否 |
是 |
一组以英文冒号分隔的键值对,用于标准或自定义参数。用英文分号分隔各对。下面列出了可视化协议定义的标准参数:
示例 : |
tqrt | 否 |
否 |
预留:忽略此参数。用于发送查询的方法。 |
响应格式
响应的格式取决于请求的 out
参数,该参数指定了预期的响应类型。请参阅以下部分,了解如何响应每种请求类型:
- JSON - 返回一个 JSON 响应,该响应包含 JavaScript 对象中的数据,而 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 Visualization 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, ...})"
以下是可用的响应对象成员:
属性 | 是否必需? |
说明 |
---|---|---|
版本 | 否 |
一个字符串编号,指定了 Google 可视化传输协议版本号。如果未指定,客户端将假定使用最新版本。 示例: |
reqId | 支持* |
一个字符串编号,表示针对此客户端的此请求的 ID。如果请求中包含此字符串,则返回相同的值。如需了解详情,请参阅请求部分中的 reqId 说明。*如果请求中未指定此参数,则无需在响应中设置。 |
status | 是 |
描述此操作成功或失败的字符串。只能是以下某个值:
示例: |
警告 | 仅限 status=warning |
包含一个或多个对象的数组,每个对象描述一个非严重问题。
对于
示例: |
错误 | 如果 status=error ,则为必需属性 |
包含一个或多个对象的数组,其中每个对象都描述了一个错误。对于 该数组具有以下字符串成员(仅为每个成员返回一个值):
示例: |
sig | 否 |
表对象的哈希值。有助于优化客户端与数据源之间的数据传输。您可以根据需要选择任何哈希算法。 如果您支持此属性,则应在未返回任何数据时返回客户端传入的值,或者在返回新数据时返回新的哈希值。 示例: |
桌子 | 否 |
采用 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 Visualization API 客户端会缓存DataTable
和sig
值。 - 客户端发送另一个数据请求,包括缓存的
tqx.sig
值。 - 数据源可以通过以下两种方式之一做出响应:
- 如果数据与上一个请求相比发生了变化,则数据源会发回新的
DataTable
和新的sig
值哈希值。 - 如果数据与上一个请求相比没有变化,则数据源会发回
status=error
、reason=not_modified
和sig=old_sig_value
。
- 如果数据与上一个请求相比发生了变化,则数据源会发回新的
- 无论是哪种情况,托管图表的网页都会收到成功响应,并可以通过调用
QueryResponse.getDataTable()
来检索DataTable
。如果数据相同,则只是表的缓存版本。
请注意,这仅适用于基于 Google Visualization 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 数据源库(来自 Google) - 处理请求和响应、根据您提供的数据创建响应表,以及实现 Google 图表工具 SQL 查询语言。
- Python 数据源库(由 Google 提供)- 用于创建响应表,以生成响应语法。不负责解析请求或实现 Google 图表工具 SQL 查询语言。
- MC-Google_Visualization(第三方)- 这是一个 PHP 服务器端库,可用于通过 PDO 为 MySQL、SQLite 和 PostgreSQL 数据库引擎实现图表工具数据源。
- bortosky-google-visualization(第三方)- 这是一个辅助库,可为 .NET 用户创建 Google Visualization API 数据表。
- GV Streamer(第三方)- GV Streamer 是一种服务器端工具,可以将来自不同来源的数据转换为对 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 查询语言。