创建跨源的浏览器端API请求
出于安全考虑,现代浏览器有一个同源策略限制这可以防止在浏览器中运行的脚本访问其他域中的资源。亚博电脑端但是,如果其他域中的服务器实现跨地域资源共享(CORS),浏览器将允许脚本访问该域中的资源。亚博电脑端
亚博Zendesk只实现CORSAPI请求使用OAuth访问令牌进行身份验证。它不为使用基本身份验证(电子邮件和密码)或Zendesk API令牌的API请求实现CORS。亚博
异常:一些Zende亚博sk API端点根本不需要任何身份验证。它们包括创建请求和搜索文章端点。CORS是为这些端点实现的。
如果一个API请求通过OAuth认证,Zendesk会在响应中包含一个特殊的“Access-C亚博ontrol-Allow-Origin”CORS头。header的值为'*',允许来自任何来源的页面的请求。这个头基本上给了浏览器访问Zendesk域中资源的权限。亚博电脑端亚博
CORS报头只包含在某些API请求的HTTP响应中,包括成功的请求(HTTP状态200、201或204)或没有找到资源(状态404)。头信息不包含在“403禁止”或“429 Too Many Requests”状态的响应中。在这些情况下,浏览器会检测到跨源错误并阻止对Zendesk域的访问。亚博请求的状态没有到达浏览器。
下面的代码片段使用OAuth身份验证创建了一个跨起源的浏览器端API请求:
var请求=新XMLHttpRequest();
varurl=“https://your_subdomain.亚博zendesk.com/api/v2/tickets/”+ticket_id+. json的;
请求.开放(“得到”,url,真正的);
请求.setRequestHeader(“授权”,“持票人”+access_token);
请求.发送();
本文的其余部分将扩展此示例。
教程-建立门票详细信息页面
本文开发的web页面允许用户仅使用浏览器获取和显示有关Support票据的信息。为保持简单,它向对象发出GET请求演出门票端点。用户在HTML表单中输入票据id。
根据API文档,用户必须是Zendesk Support的代理或管理员才能使用Show Ticket端点。亚博(管理员拥有代理的所有权限。)
这一限制还意味着web开发人员必须是代理或管理员,才能在开发过程中测试页面。
开发页面包括以下任务:
如需下载已完成的项目文件,请单击ticket_details.zip.
免责声明: 亚博Zendesk提供本文仅用于教学目的。亚博Zendesk不支持或保证该代码。亚博Zendesk也不支持JavaScript等第三方技术。
在Zendesk Support中创建OAuth客户亚博端
要使用OAuth身份验证,您必须首先在Zendesk Support中创建OAuth客户端来注册应用程序。亚博
必须是管理员才能创建OAuth客户端。
创建OAuth客户端
在管理中心,按应用程序和集成图标(),然后选择api>亚博Zendesk API>OAuth客户.
点击页面右侧的加号(+)图标。
填写表格。看到在Zendesk上注册应用程序亚博获取详细信息。
为重定向url字段,输入您将在本教程中构建的网页的URL。展望未来,文件将被命名ticket_details.html.
如果您可以访问web服务器,请输入未来文件的完整url:
https://www.example.com/my_site/ticket_details.html
如果您没有访问web服务器的权限,您可以在计算机上安装并运行本地web服务器,例如XAMPP。指定localhost url为重定向url。例子:
http://localhost/my_site/ticket_details.html
有关XAMPP的更多信息和下载方法,请参见Apache的朋友的网站。
设计页面布局
本教程由一个简单的HTML文件、一个CSS和一个JavaScript文件组成。
设计页面布局
创建一个名为ticket_details.html.
添加以下HTML到文件中,然后保存它:
<!文档类型超文本标记语言>
<超文本标记语言>
<头>
<元字符集="utf - 8"/>
<标题>得到票的细节标题>
<链接rel="样式表"href="styles.css">
头>
<身体>
<h4>输入机票idh4>
<形式id="买到">
<输入类型="文本"id="ticket-id"占位符="票id"/>
<按钮id="get-btn">得到票!按钮>
形式>
<divid="error-msg">div>
<divid="细节">div>
<脚本src="scripts.js">脚本>
身体>
超文本标记语言>
页面设计由3个展示元素组成:
- 一个HTML表单,从用户那里获取票据id
- 一个div标签来显示票务信息
- 用于显示任何错误消息的div标记
如果对布局感到满意,可以关闭HTML文件。在本教程中,您不会再碰它。
创建一个名为styles.css在同一文件夹中,将以下规则添加到文件中并保存:
身体{
字体-家庭:无-衬线;
字体-大小:85%;
保证金:20.px;
}
#细节{
显示:没有一个;
保证金-前:40px;
}
#细节页{
行-高度:150%;
}
#错误-味精{
显示:没有一个;
保证金-前:40px;
}
类默认隐藏了"error-msg"和"details" div
显示:没有;
设置。脚本只在需要时显示每个div。除非您想调整样式,否则可以关闭CSS文件。在本教程中,您不会再碰它。
创建一个名为scripts.js然后添加以下JavaScript到文件中:
函数初始化(){
//重置页面
文档.getElementById(“error-msg”).风格.显示=“没有”;
文档.getElementById(“细节”).风格.显示=“没有”;
//函数体
}
函数getTicket(事件){
//函数体
}
窗口.addEventListener(“负载”,初始化,假);
文档.getElementById(“get-btn”).addEventListener(“点击”,getTicket,假);
该脚本添加了两个事件监听器。第一个监听要加载的页面。如果检测到,则运行
init ()
函数。第二个监听窗体按钮的单击。如果检测到,则运行getTicket ()
函数。这个实用的布局在浏览器中应该是这样的:
用户请求票据后:
保存所有3个文件,ticket_details.html,styles.css,scripts.js,转到web服务器要提供服务的文件夹。确保url为ticket_details.html与您在OAuth客户端中指定的重定向url相同。看到在Zendesk Support中创建OAuth客户亚博端.
从用户获取票据id
您必须使用JavaScript而不是HTML表单提交来获得用户提交的票据id。脚本需要id向Zendesk API发出AJAX请求。亚博
从用户获取票据id
在scripts.js文件中,替换“//函数体”注释
getTicket ()
使用以下代码段执行函数:事件.preventDefault();
文档.getElementById(“error-msg”).风格.显示=“没有”;//清除错误信息
varticket_id=文档.getElementById(“ticket-id”).价值;
如果((!ticket_id)||isNaN(ticket_id)){
showError('糟糕,字段值应该是票证id ');
返回;
}
//在本地存储中检查token
它是如何工作的
该脚本执行以下操作:
隐藏了error-msgDiv,以防用户之前提交id的尝试导致表单验证错误消息。
将票据id分配给ticket_id变量。
对字段的值执行基本验证,以确保用户输入的值是一个数字。
显示任何验证错误并结束脚本。
的
showError ()
函数是稍后添加的自定义帮助函数。方法中添加错误消息error-msgDiv,然后使Div可见。
检查现有的访问令牌
在使用票据id发出API请求之前,您应该检查用户是否已经拥有OAuth访问令牌。在本教程的后面部分,您将更新脚本以获取访问令牌,然后将其作为数据项添加到浏览器中localStorage对象。
检查现有的令牌
在
getTicket ()
函数,将"// check for token in local storage"注释替换为以下代码段:如果(localStorage.getItem(“zauth”)){
varaccess_token=localStorage.getItem(“zauth”);
makeRequest(access_token,ticket_id);
}其他的{
localStorage.setItem(“ticket_id”,ticket_id);
startAuthFlow();
}
它是如何工作的
该脚本执行以下操作:
在浏览器的本地存储中检查令牌:
如果(localStorage.getItem(“zauth”)){
...
}
存储中的令牌(如果存在)将被命名zauth.您将在后面的教程中命名它。
如果它找到令牌,就使用它来发出请求。
的
makeRequest ()
在本教程后面定义。如果它没有找到令牌,它会保存票据id,以便从Zendesk授权页面返回后恢复表单的状态:亚博
localStorage.setItem(“ticket_id”,ticket_id);
然后启动授权流。的
startAuthFlow ()
函数在下一节中定义。
在这一点上,脚本执行分为两个分支:
API请求分支——脚本使用现有的令牌进行API请求并显示结果:
makeRequest(access_token,ticket_id);
OAuth分支——脚本启动认证流,从Zendesk获取令牌,然后重新加入API请求分支:亚博
startAuthFlow();
本教程将跟随重新加入API请求分支的OAuth分支。
启动授权流
的隐式拨款流用于获取浏览器端API请求的OAuth访问令牌。
隐式授权流类似于更常见的授权流授权代码授予流程,除非您直接请求一个令牌,而不是授权代码。如果最终用户授予你的应用访问权限,令牌将立即在重定向URL中发送。有关更多信息,请参见隐式拨款流在支持帮助中心。
启动授权流
后添加以下函数
getTicket ()
功能:函数startAuthFlow(){
var端点=“https://your_subdomain.亚博zendesk.com/oauth/authorizations/new”;
varurl_params=“?”+
“response_type =令牌”+“&”+
“redirect_uri = your_redirect_url”+“&”+
“client_id = your_unique_identifier '+“&”+
“范围= '+encodeURIComponent(阅读写的);
窗口.位置=端点+url_params;
}
在端点中指定Zendesk亚博子域。
指定您的
redirect_uri
和client_id
值,这些值在前面创建的OAuth客户机中定义。重要的
- 的
redirect_uri
值必须匹配重定向url在客户端界面。 - 的
client_id
被命名为唯一标识符在客户端界面。
- 的
它是如何工作的
该函数使用所需的OAuth参数构建一个url。然后,它使用url在用户的浏览器中打开Zendesk授权页面。亚博
处理重定向
在用户授权访问你的应用程序后,Zendesk使用你的重定向uri重新打开亚博ticket_details.html页面。亚博Zendesk将访问令牌作为url参数:
{redirect_url}# access_token=f27851bd085c45ad9027a2ee223bde4f9a07171&范围=读+写&token_type=持票人
您可以监听页面加载以处理重定向。如果加载的页面是ticket_details.html并且url包含“access_token”,脚本应该提取令牌并使用它来发出API请求。
现有的init ()
函数在每次加载页面时运行。这是一个检查每个加载页面的url是否存在访问令牌的好地方。
处理重定向
在
init ()
函数,将"// Function body"注释替换为以下代码段:varurl=窗口.位置.href;
如果(url.indexOf(“your_redirect_url”)= = !-1){
如果(url.indexOf(“access_token = ')= = !-1){
varaccess_token=readUrlParam(url,“access_token”);
localStorage.setItem(“zauth”,access_token);
varticket_id=localStorage.getItem(“ticket_id”);
文档.getElementById(“ticket-id”).价值=ticket_id;
窗口.位置.哈希="";
makeRequest(access_token,ticket_id);
}
如果(url.indexOf(“错误= ')= = !-1){
varerror_desc=readUrlParam(url,“error_description”);
var味精='授权错误:'+error_desc;
showError(味精);
}
}
取代your_redirect_url带有自己url的占位符。
它是如何工作的
该脚本执行以下任务:
获取重定向页面的完整url:
varurl=窗口.位置.href;
确保页面url与您提供给Zendesk的重定向url匹配。亚博
如果(url.indexOf(“http://localhost/testing/cors/ticket_details.html”)= = !-1){
...
}
脚本会忽略浏览器中可能加载的所有其他页面。
请注意: JavaScript
indexOf ()
如果未找到字符串,则返回-1。检查字符串"access_token="是否在url中:
如果(url.indexOf(“access_token = ')= = !-1){
...
}
如果找到该字符串,则从url中获取令牌的值并将其存储以供重用:
varaccess_token=readUrlParam(url,“access_token”);
localStorage.setItem(“zauth”,access_token);
的
readUrlParam ()
函数是稍后添加的自定义帮助函数。它提取指定url参数的值并返回该值。检索存储的票据id并恢复表单的状态。
清除浏览器地址窗口中的url参数,这样访问令牌就不会那么暴露了:
窗口.位置.哈希="";
方法来发出请求
makeRequest ()
函数,您将在下一节中添加它。如果url中有字符串"error=",则显示错误消息。
如果用户决定不授予对应用程序的访问权限,则重定向URL将包含错误和error_description通知脚本事实的参数。
发出API请求
最后一步是使用访问令牌发出API请求。如果脚本执行到此点,则令牌应该存储在浏览器的本地存储中。
进行API请求
控件中添加以下函数scripts.js文件:
函数makeRequest(令牌,ticket_id){
var请求=新XMLHttpRequest();
请求.onreadystatechange=函数(){
如果(请求.请求处理= = =4){
如果(请求.状态= = =200){
var数据=JSON.解析(请求.响应结果字符串);
var票=数据.票;
vardetails_html=
“< p >”+
的主题:+票.主题+“< br / >”+
“状态:< >强”+票.状态.包含()+' < /强> < br / > '+
的创建:+票.created_at+
' < / p > ';
文档.getElementById(“细节”).innerHTML=details_html;
文档.getElementById(“细节”).风格.显示=“继承”;
}其他的{
文档.getElementById(“细节”).风格.显示=“没有”;
如果(请求.状态= = =0){
showError(他说,这个请求有问题。请确保您是Zendesk Support的代理或管理员。”亚博);
}其他的{
showError(“哎呀,请求返回了\"”+请求.状态+' '+请求.statusText+“\”。”);
}
}
}
};
varurl=“https://your_subdomain.亚博zendesk.com/api/v2/tickets/”+ticket_id+. json的;
请求.开放(“得到”,url,真正的);
请求.setRequestHeader(“授权”,“持票人”+令牌);
请求.发送();
}
取代your_subdomain的占位符url函数末尾的变量赋值。
它是如何工作的
第一条语句创建了一个JavaScript请求对象:
var请求=新XMLHttpRequest();
其余的功能由两部分组成:
- 从服务器获得响应后运行的回调函数
- API请求本身
回调函数被首先定义,即使它在请求发出后运行。该脚本执行以下任务:
定义函数:
请求.onreadystatechange=函数(){
...
}
onreadystatechange
时调用的事件处理程序请求处理
属性的变化。(见下一行。)每次属性更改时,脚本都会运行回调函数。检查
请求处理
属性查看请求是否完成:如果(请求.请求处理= = =4){
...
}
一个
请求处理
4表示操作结束。看到请求处理Mozilla开发者网络上的文档。检查API请求是否成功:
如果(请求.状态= = =200){
...
}
HTTP状态为200表示GET API请求成功。一般情况下,GET和PUT请求的值为200,POST请求的值为201,DELETE请求的值为204。看到亚博Zendesk API文档.
将数据从JSON字符串转换为表示票据的JavaScript对象:
var数据=JSON.解析(请求.响应结果字符串);
var票=数据.票;
构建一个HTML字符串来显示票证信息:
vardetails_html=
“< p >”+
的主题:+票.主题+“< br / >”+
...
控件中插入HTML细节Div并使Div可见。
如果请求不成功(如果返回的不是状态200),则检查是否存在可能的CORS错误。CORS报头不包含在某些HTTP响应中,包括带有“403 Forbidden”或“429 Too Many Requests”状态的响应。在这些情况下,浏览器会检测到跨源错误并阻止对Zendesk域的访问。亚博请求的状态永远不会到达浏览器。
使用JavaScript检查CORS错误没有简单的方法,但是当CORS错误发生时返回的HTTP状态为0。请注意,值为0并不能保证问题是CORS错误。
如果状态代码不是200或0,则显示状态代码和错误描述,例如“404 not found”。
发出API请求的代码执行以下任务。
使用票据id构建API端点url:
varurl=“https://your_subdomain.亚博zendesk.com/api/v2/tickets/”+ticket_id+. json的;
看到戏票详见API文档。
配置请求:
请求.开放(“得到”,url,真正的);
设置跨源API请求所需的授权头:
请求.setRequestHeader(“授权”,“持票人”+令牌);
发送请求:
请求.发送();
添加helper函数
该脚本使用两个自定义助手函数来执行重复任务。将下面的两个函数添加到scripts.js文件。
函数showError(味精){
文档.getElementById(“error-msg”).innerHTML=“< p >”+味精+' < / p > ';
文档.getElementById(“error-msg”).风格.显示=“继承”;
}
函数readUrlParam(url,参数){
参数+ =“=”;
如果(url.indexOf(参数)= = !-1){
var开始=url.indexOf(参数)+参数.长度;
var价值=url.字符串的子串(开始);
如果(价值.indexOf(“&”)= = !-1){
var结束=价值.indexOf(“&”);
价值=价值.子字符串(0,结束);
}
返回价值;
}其他的{
返回假;
}
}
它是如何工作的
的showError ()
Helper是自解释的。
即使readUrlParam ()
函数由基本的JavaScript字符串操作组成,它可能需要更多的解释。该函数执行以下任务:
的值参数存在于url在尝试得到它的值之前:
如果(url.indexOf(参数)= = !-1){
如果参数字符串,取字符串的第一个字符的下标,然后右移参数字符串的长度来获取值的第一个字符的索引:
var开始=url.indexOf(参数)+参数.长度;
获取从值的第一个字符开始的字符串:
var价值=url.字符串的子串(开始);
通过查找"&"字符来检查提取的字符串中的其他参数:
如果(价值.indexOf(“&”)= = !-1){
如果找到,查找第一个“&”字符的位置:
var结束=价值.indexOf(“&”);
获取子字符串从开头到"&"字符的位置:
价值=价值.子字符串(0,结束);
此时,应该只保留参数值。
代码完成
保存或上传scripts.js到要由web服务器提供服务的文件夹。它应该在同一个文件夹ticket_details.html.确保url为ticket_details.html与您在OAuth客户端中指定的重定向url相同。看到在Zendesk Support中创建OAuth客户亚博端.
函数初始化(){
//重置页面
文档.getElementById(“error-msg”).风格.显示=“没有”;
文档.getElementById(“细节”).风格.显示=“没有”;
varurl=窗口.位置.href;
如果(url.indexOf(“your_redirect_url”)= = !-1){
如果(url.indexOf(“access_token = ')= = !-1){
varaccess_token=readUrlParam(url,“access_token”);
localStorage.setItem(“zauth”,access_token);
varticket_id=localStorage.getItem(“ticket_id”);
文档.getElementById(“ticket-id”).价值=ticket_id;
窗口.位置.哈希="";
makeRequest(access_token,ticket_id);
}
如果(url.indexOf(“错误= ')= = !-1){
varerror_desc=readUrlParam(url,“error_description”);
var味精='授权错误:'+error_desc;
showError(味精);
}
}
}
函数getTicket(事件){
事件.preventDefault();
文档.getElementById(“error-msg”).风格.显示=“没有”;//清除错误信息
varticket_id=文档.getElementById(“ticket-id”).价值;
如果((!ticket_id)||isNaN(ticket_id)){
showError('糟糕,字段值应该是票证id ');
返回;
}
如果(localStorage.getItem(“zauth”)){
varaccess_token=localStorage.getItem(“zauth”);
makeRequest(access_token,ticket_id);
}其他的{
localStorage.setItem(“ticket_id”,ticket_id);
startAuthFlow();
}
}
函数startAuthFlow(){
var端点=“https://your_subdomain.亚博zendesk.com/oauth/authorizations/new”;
varurl_params=“?”+
“response_type =令牌”+“&”+
“redirect_uri = your_redirect_url”+“&”+
“client_id = your_unique_identifier '+“&”+
“范围= '+encodeURIComponent(阅读写的);
窗口.位置=端点+url_params;
}
函数makeRequest(令牌,ticket_id){
var请求=新XMLHttpRequest();
请求.onreadystatechange=函数(){
如果(请求.请求处理= = =4){
如果(请求.状态= = =200){
var数据=JSON.解析(请求.响应结果字符串);
var票=数据.票;
vardetails_html=
“< p >”+
的主题:+票.主题+“< br / >”+
“状态:< >强”+票.状态.包含()+' < /强> < br / > '+
的创建:+票.created_at+
' < / p > ';
文档.getElementById(“细节”).innerHTML=details_html;
文档.getElementById(“细节”).风格.显示=“继承”;
}其他的{
文档.getElementById(“细节”).风格.显示=“没有”;
如果(请求.状态= = =0){
showError(他说,这个请求有问题。请确保您是Zendesk Support的代理或管理员。”亚博);
}其他的{
showError(“哎呀,请求返回了\"”+请求.状态+' '+请求.statusText+“\”。”);
}
}
}
};
varurl=“https://your_subdomain.亚博zendesk.com/api/v2/tickets/”+ticket_id+. json的;
请求.开放(“得到”,url,真正的);
请求.setRequestHeader(“授权”,“持票人”+令牌);
请求.发送();
}
函数showError(味精){
文档.getElementById(“error-msg”).innerHTML=“< p >”+味精+' < / p > ';
文档.getElementById(“error-msg”).风格.显示=“继承”;
}
函数readUrlParam(url,参数){
参数+ =“=”;
如果(url.indexOf(参数)= = !-1){
var开始=url.indexOf(参数)+参数.长度;
var价值=url.字符串的子串(开始);
如果(价值.indexOf(“&”)= = !-1){
var结束=价值.indexOf(“&”);
价值=价值.子字符串(0,结束);
}
返回价值;
}其他的{
返回假;
}
}
窗口.addEventListener(“负载”,初始化,假);
文档.getElementById(“get-btn”).addEventListener(“点击”,getTicket,假);