• 关于 获取页面title例子 的搜索结果

问题

SmartGWT学习整理 2、理解核心中的核心DataSource 400 请求报错 

kun坤 2020-05-29 11:00:58 2 浏览量 回答数 1

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:30 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:30 0 浏览量 回答数 0

中小企业与商标那些事

企业品牌保护从商标开始,如何挑选一家靠谱的渠道注册商标,解读品牌权益维护的重要节点。

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:30 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:29 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:30 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:29 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:29 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 同源策略 跨域访问,或者说 JavaScript 的跨域访问问题,是浏览器出于安全考虑而设置的一个限制,即同源策略。举例说明,当 A,B 两个网站属于不同的域时,如果来自于 A 网站的页面中的 JavaScript 代码希望访问 B 网站的时候,浏览器会拒绝该访问。 然而,在实际应用中,经常会有跨域访问的需求。比如用户的网站 www.a.com,后端使用了 OSS,在网页中提供了使用 JavaScript 实现的上传功能,但是在该页面中,只能向 www.a.com 发送请求,向其他网站发送的请求都会被浏览器拒绝。这样会导致用户上传的数据必须从www.a.com 中转。如果设置了跨域访问的话,用户就可以直接上传到 OSS 而无需从 www.a.com 中转。 CORS 介绍 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS),是 HTML5 提供的标准跨域解决方案,具体的CORS规则可以参考W3C CORS规范。 CORS 是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互。浏览器在识别到发起的请求是跨域请求的时候,会将Origin的Header加入HTTP请求发送给服务器,比如上面那个例子,Origin的Header就是www.a.com。服务器端接收到这个请求之后,会根据一定的规则判断是否允许该来源域的请求,如果允许的话,服务器在返回的响应中会附带上Access-Control-Allow-Origin这个Header,内容为www.a.com来表示允许该次跨域访问。如果服务器允许所有的跨域请求的话,将Access-Control-Allow-Origin的Header设置为*即可,浏览器根据是否返回了对应的Header来决定该跨域请求是否成功,如果没有附加对应的Header,浏览器将会拦截该请求。 以上描述的仅仅是简单情况,CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的请求。预检机制是一种保护机制,防止资源被本来没有权限的请求修改。浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求。如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。 只有同时满足以下两个条件才不需要发送预检请求: 请求方法是如下之一: GET HEAD POST 所有的Header都在如下列表中: Cache-Control Content-Language Content-Type Expires Last-Modified Pragma 预检请求会附带一些关于接下来的请求的信息给服务器,主要有以下几种: Origin:请求的源域信息 Access-Control-Request-Method:接下来的请求类型,如POST、GET等 Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表 服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,信息返回同样是通过Header完成的: Access-Control-Allow-Origin:允许跨域的Origin列表 Access-Control-Allow-Methods:允许跨域的方法列表 Access-Control-Allow-Headers:允许跨域的Header列表 Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表 Access-Control-Max-Age:最大的浏览器缓存时间,单位为s 浏览器会根据以上的返回信息综合判断是否继续发送实际请求。当然,如果没有这些Header浏览器会直接阻止接下来的请求。 说明 这里需要再次强调的一点是,以上行为都是浏览器自动完成的,用户无需关注这些细节。如果服务器配置正确,那么和正常非跨域请求是一样的。 CORS主要使用场景 CORS使用一定是在使用浏览器的情况下,因为控制访问权限的是浏览器而非服务器。因此使用其它的客户端的时候无需关心任何跨域问题。 使用CORS的主要应用就是在浏览器端使用Ajax直接访问OSS的数据,而无需走用户本身的应用服务器中转。无论上传或者下载。对于同时使用OSS和使用Ajax技术的网站来说,都建议使用CORS来实现与OSS的直接通信。 OSS对CORS的支持 OSS提供了CORS规则的配置从而根据需求允许或者拒绝相应的跨域请求。该规则是配置在Bucket级别的。详情可以参考PutBucketCORS。 CORS请求的通过与否和OSS的身份验证等是完全独立的,即OSS的CORS规则仅仅是用来决定是否附加CORS相关的Header的一个规则。是否拦截该请求完全由浏览器决定。 使用跨域请求的时候需要关注浏览器是否开启了Cache功能。当运行在同一个浏览器上分别来源于www.a.com和www.b.com的两个页面都同时请求同一个跨域资源的时候,如果www.a.com的请求先到达服务器,服务器将资源带上Access-Control-Allow-Origin的Header为www.a.com返回给用户。这个时候www.b.com又发起了请求,浏览器会将Cache的上一次请求返回给用户,这个时候Header的内容和CORS的要求不匹配,就会导致后面的请求失败。 说明 目前OSS的所有Object相关的接口都提供了CORS相关的验证,另外Multipart相关的接口目前也已经完全支持CORS验证。 GET请求跨域示例 这里举一个使用Ajax从OSS获取数据的例子。为了简单起见,使用的Bucket都是public,访问私有的Bucket的CORS配置是完全一样的,只需要在请求中附加签名即可。 简单开始 首先创建一个Bucket,这里举例为oss-cors-test,将权限设置为public-read,然后这里创建一个test.txt的文本文档,上传到这个Bucket。 单击此处,获取test.txt的访问地址。 说明 请将下文中的地址换成自己试验的地址。 首先用curl直接访问: curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt just for test 可见现在已经能正常访问了。 那么我们现在再试着使用Ajax技术来直接访问这个网站。我们写一个最简单的访问的HTML,可以将以下代码复制到本地保存成html文件然后使用浏览器打开。因为没有设置自定义的头,因此这个请求是不需要预检的。 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="./functions.js"></script> </head> <body> <script type="text/javascript"> // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. xhr = null; } return xhr; } // Make the actual CORS request. function makeCorsRequest() { // All HTML5 Rocks properties support CORS. var url = 'http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/test.txt'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // Response handlers. xhr.onload = function() { var text = xhr.responseText; var title = text; alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); } </script> <p align="center" style="font-size: 20px;"> <a href="#" onclick="makeCorsRequest(); return false;">Run Sample</a> </p> </body> </html> 打开文件后点击链接(以Chrome为例),提示该链接无法访问。 利用Chrome的开发者工具来查看错误原因。 这里告诉我们是因为没有找到Access-Control-Allow-Origin这个头。显然,这就是因为服务器没有配置CORS。 再进入Header界面,可见浏览器发送了带Origin的Request,因此是一个跨域请求,在Chrome上因为是本地文件所以Origin是null。 设置 Bucket CORS知道了上文的问题,那么现在可以设置Bucket相关的CORS来使上文的例子能够执行成功。为了直观起见,这里使用控制台来完成CORS的设置。如果用户的CORS设置不是很复杂,也建议使用控制台来完成CORS设置。CORS设置的界面如下: CORS设置是由一条一条规则组成的,真正匹配的时候会从第一条开始逐条匹配,以最早匹配上的规则为准。现在添加第一条规则,使用最宽松的配置: 这里表示的意思就是所有的Origin都允许访问,所有的请求类型都允许访问,所有的Header都允许,最大的缓存时间为1s。 配置完成之后重新测试,结果如下: 可见现在已经可以正常访问请求了。 因此排查问题来说,如果想要排除跨域带来的访问问题,可以将CORS设置为上面这种配置。这种配置是允许所有的跨域请求的一种配置,因此如果这种配置下依然出错,那么就表明错误出现在其他的部分而不是CORS。 除了最宽松的配置之外,还可以配置更精细的控制机制来实现针对性的控制。比如对于这个场景可以使用如下最小的配置匹配成功: 因此对于大部分场景来说,用户最好根据自己的使用场景来使用最小的配置以保证安全性。 利用跨域实现POST上传 这里提供一个更复杂的例子,这里使用了带签名的POST请求,而且需要发送预检请求。详情请参见PostObjectSample。 说明 将上面的代码下载下来之后,将以下对应的部分全部修改成自己对应的内容,然后使用自己的服务器运行起来。 这里继续使用上文oss-cors-test这个Bucket来进行测试,在测试之前先删除所有的CORS相关的规则,恢复初始状态。 访问这个网页,选择一个文件上传。 同样打开开发者工具,可以看到以下内容,根据上面的Get的例子,很容易明白同样发生了跨域的错误。不过这里与Get请求的区别在于这是一个带预检的请求,所以可以从图中看到是OPTIONS的Response没有携带CORS相关的Header然后失败了。 那么我们根据对应的信息修改Bucket的CORS配置: 再重新运行,可见已经成功了,从控制台中也可以看到新上传的文件。 测试一下内容: $curl http://oss-cors-test.oss-cn-hangzhou.aliyuncs.com/events/1447312129218-test1.txt post object test CORS配置的一些注意事项 CORS配置一共有以下几项: 来源:配置的时候要带上完整的域信息,比如示例中 http://10.101.172.96:8001. 注意不要遗漏了协议名如http,如果端口号不是默认的还要带上端口号之类的。如果不确定的话,可以打开浏览器的调试功能查看Origin头。这一项支持使用通配符*,但是只支持一个,可以根据实际需要灵活配置。 Method:按照需求开通对应的方法即可。 Allow Header:允许通过的Header列表,因为这里容易遗漏Header,因此建议没有特殊需求的情况下设置为*。大小写不敏感。 Expose Header:暴露给浏览器的Header列表,不允许使用通配符。具体的配置需要根据应用的需求来选择,只暴露需要使用的Header,如ETag等。如果不需要暴露这些信息,这里可以不填。如果有特殊需求可以单独指定,大小写不敏感。 缓存时间:如果没有特殊情况可以酌情设置的大一点,比如60s。 因此,CORS的一般配置方法就是针对每个可能的访问来源单独配置规则,尽量不要将多个来源混在一个规则中,多个规则之间最好不要有覆盖冲突。其他的权限只开放需要的权限即可。 一些错误排查经验 在调试类似程序的时候,很容易发生一种情况就是将其他错误和CORS错误弄混淆了。 举个例子,当用户因为签名错误访问被拒绝的时候,因为权限验证发生在CORS验证之前,因此返回的结果中并没有带上CORS的Header信息,有些浏览器就会直接报CORS出错,但是实际服务器端的CORS配置是正确的。对于这种情况,我们有两种方式: 查看HTTP请求的返回值,因为CORS验证是一个独立的验证,并不影响主干流程,因此像403之类的返回值不可能是由CORS导致的,需要先排除程序原因。如果之前发送了预检请求,那么可以查看预检请求的结果,如果预检请求中返回了正确的CORS相关的Header,那么表示真实请求应该是被服务器端所允许的,因此错误只可能出现在其他的方面。 将服务器端的CORS设置按照如上文所示,改成允许所有来源所有类型的请求都通过的配置,再重新验证。如果还是验证失败,表明有其他的错误发生。

2019-12-01 23:13:30 0 浏览量 回答数 0

问题

深入理解Magento – 第七章 – 自定义Magento系统配置 :报错

kun坤 2020-06-14 15:21:31 0 浏览量 回答数 1

问题

第七章 – 自定义Magento系统配置:配置报错 

kun坤 2020-06-02 14:47:13 0 浏览量 回答数 1

问题

深入理解Magento – 第七章 – 自定义Magento系统配置 - 配置报错

montos 2020-06-03 20:29:30 2 浏览量 回答数 1

回答

一般都是后台直接拼接好JSON格式返回,页面解析。 给你看个例子: <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>四级联动下拉列表选中值保持不变</title> <style type="text/css"> div #tip { font:consolas normal 20px; color:blue; } </style> <script type="text/javascript" src="js/jquery-1.4.4.min.js"></script> <script type="text/javascript"> $(function() { $("#province").change(function() { if ($("#province").val() == '0') { $("#city").html(''); $("#county").html(''); $("#town").html(''); return; } $("#tip").append("<span>请求Ajax获取城市...<br></span>"); $.get("ajax.do", {type:'1', value:$("#province").val(), time:new Date() },function(data) { $("#tip").append("<span>"+$("#province").val()+"下城市信息获取成功<br></span>"); $("#city").html('<option value="0" selected="selected">请选择一个市</option>'); var pros = eval(data); for (var i=0;i<pros.length;i++) { var cityName = pros[i].name; var cityValue = pros[i].value; var opt = $("<option value='" + cityValue + "'>"+cityName+"</option>"); $("#city").append(opt); } }); }); $("#city").change(function() { $("#tip").append("<span>请求Ajax获取县...<br></span>"); if ($("#city").val() == '0') { $("#county").html(''); $("#town").html(''); return; } $.get("ajax.do", {type:'2', value:$("#city").val(), time:new Date() },function(data) { $("#tip").append("<span>"+$("#city").val()+"下县的信息获取成功<br></span>"); $("#county").html('<option value="0" selected="selected">请选择一个县</option>'); var pros = eval(data); for (var i=0;i<pros.length;i++) { var countyName = pros[i].name; var countyValue = pros[i].value; var opt = $("<option value='" + countyValue + "'>"+countyName+"</option>"); $("#county").append(opt); } }); }); $("#county").change(function() { $("#tip").append("<span>请求Ajax获取镇...<br></span>"); if ($("#county").val() == '0') { $("#town").html(''); return; } $.get("ajax.do", {type:'3', value:$("#county").val(), time:new Date() },function(data) { $("#tip").append("<span>"+$("#county").val()+"下镇的信息获取成功<br></span>"); $("#town").html(''); var pros = eval(data); for (var i=0;i<pros.length;i++) { var townName = pros[i].name; var townValue = pros[i].value; var opt = $("<option value='" + townValue + "'>"+townName+"</option>"); $("#town").append(opt); } }); }); }); </script> </head> <body> 省:<select id="province"> <option value="0" selected="selected">请选择一个省</option> <option value="hubei">湖北</option> </select> 市:<select id="city"></select> 县:<select id="county"></select> 镇:<select id="town"></select> <div id="tip"></div> </body> </html> package com.servlet.ajax; import java.io.IOException;import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class AjaxServlet */ @WebServlet("/ajax.do") public class AjaxServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * Default constructor. */ public AjaxServlet() { // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); String type = request.getParameter("type"); String value = request.getParameter("value"); PrintWriter pw = response.getWriter(); System.out.println(type); if ("1".equals(type) && value != null && !"".equals(value)) { // 根据省获取市 // 这里可以从数据库获取 if ("hubei".equals(value)) { StringBuilder citys = new StringBuilder(); citys.append("["); citys.append("{name:'武汉',value:'hubei001'},"); citys.append("{name:'襄阳',value:'hubei002'}"); citys.append("]"); System.out.println(citys.toString()); pw.print(citys.toString()); } } else if ("2".equals(type) && value != null && !"".equals(value)) { // 根据省获取县 // 这里可以从数据库获取 StringBuilder countries = new StringBuilder(); if ("hubei001".equals(value)) { countries.append("["); countries.append("{name:'AAA县',value:'wuhan001'},"); countries.append("{name:'BBB县',value:'wuhan002'},"); countries.append("{name:'CCC县',value:'wuhan003'}"); countries.append("]"); } else if ("hubei002".equals(value)) { countries.append("["); countries.append("{name:'南漳县',value:'xiangyang001'},"); countries.append("{name:'古城县',value:'xiangyang002'}"); countries.append("]"); } System.out.println(countries.toString()); pw.print(countries.toString()); } else if ("3".equals(type) && value != null && !"".equals(value)) { StringBuilder towns = new StringBuilder(); if ("wuhan001".equals(value)) { towns.append("["); towns.append("{name:'AAA镇',value:'wuhan001'},"); towns.append("{name:'BBB镇',value:'wuhan002'},"); towns.append("{name:'CCC镇',value:'wuhan003'}"); towns.append("]"); } else if ("wuhan002".equals(value)) { towns.append("["); towns.append("{name:'CCC镇',value:'wuhan001'},"); towns.append("{name:'DDD镇',value:'wuhan002'},"); towns.append("{name:'EEE镇',value:'wuhan003'}"); towns.append("]"); } else if ("wuhan003".equals(value)) { towns.append("["); towns.append("{name:'FFF镇',value:'wuhan001'},"); towns.append("{name:'GGG镇',value:'wuhan002'}"); towns.append("]"); } else if ("xiangyang001".equals(value)) { towns.append("["); towns.append("{name:'WWW镇',value:'wuhan001'},"); towns.append("{name:'RRR镇',value:'wuhan002'}"); towns.append("]"); } else if ("xiangyang002".equals(value)) { towns.append("["); towns.append("{name:'XXX镇',value:'wuhan001'},"); towns.append("{name:'YYY镇',value:'wuhan002'}"); towns.append("]"); } System.out.println(towns.toString()); pw.print(towns.toString()); } } } 答案来源网络,供参考,希望对您有帮助

问问小秘 2019-12-02 03:03:01 0 浏览量 回答数 0

问题

如何实现跨域资源共享(CORS)?

青衫无名 2019-12-01 21:38:51 1660 浏览量 回答数 0

问题

深入理解Magento – 第六章 – 高级Magento模型 :报错

kun坤 2020-06-14 15:19:25 0 浏览量 回答数 1

问题

深入理解Magento – 第六章 – 高级Magento模型:配置报错 

kun坤 2020-06-02 14:47:07 2 浏览量 回答数 1

问题

深入理解Magento – 第六章 – 高级Magento模型 - Magento报错

montos 2020-06-03 20:30:01 2 浏览量 回答数 1

回答

Re钉钉微应用如何打开本地app (Android) 经测试,免登认证已成功,执行 dd.device.launcher.checkInstalledApps 失败报not authorized ------------------------- 回 2楼识器的帖子 你好,我参考了例子,我用调试工具获取的signature 已自己生成的对比,是一致的,但是就是在执行 dd.device.launcher.checkInstalledApps报未授权not authorized    errCode:7 ------------------------- 回 4楼识器的帖子 按你所说,我把dd 去掉了,还是不可以 ------------------------- Re钉钉微应用如何打开本地app (Android) 为什么我先访问action 签名后回到页面会认证说权限校验失败   @RequestMapping(value="/dd/openCoreMail.action")         public String openCoreMail(HttpServletRequest request,ModelMap model){                 String url=request.getRequestURL().toString();                 String querString=request.getQueryString();                 if(!StringUtils.isEmpty(querString)&&(!querString.equals("null"))){                         try {                                 querString=URLEncoder.encode(querString, "UTF-8");                         } catch (UnsupportedEncodingException e) {                                 e.printStackTrace();                         }                 }else{                         querString=null;                 }                 String result=AuthHelper.getConfig(url,querString);                         JSONObject  jobj=JSONObject.fromObject(result);                 System.out.println(result);                 Map map =new HashMap();                 map.put("SIGNATURE", jobj.getString("signature"));                 map.put("NONCESTR", jobj.getString("nonceStr"));                 map.put("TIMESTAMP", jobj.getString("timeStamp"));                 map.put("CORPID", Env.CORP_ID);                 map.put("APPID", null);                 model.addAttribute("ROOT",map);                 return "dingTalk/openCoreMail"; } 下面是页面 <%@ page language="java" contentType="text/html; charset=UTF-8"         pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://com/hbglobal/taglib/myplug" prefix="Ding"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>openCoreMail</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/dwr/engine.js"></script>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/dwr/util.js"></script>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/dwr/interface/MobileMeetingAction.js"></script>         <script src='${pageContext.request.contextPath}/js/jquery-1.11.3.js'></script>         <script                 src='${pageContext.request.contextPath}/js/jquery-migrate-1.2.1.min.js'></script>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/js/dingtalk.js"></script>         <script type="text/javascript">                         dd.config({                                 agentId : '${ROOT.APPID}',                                 corpId : '${ROOT.CORPID}',                                 timeStamp : '${ROOT.TIMESTAMP}',                                 nonceStr : '${ROOT.NONCESTR}',                                 signature : '${ROOT.SIGNATURE}',                                 jsApiList : [ 'device.notification.alert',                                                 'device.notification.confirm',                                                 'runtime.permission.requestAuthCode',                                                 'runtime.permission.requestJsApis',                                                 'device.launcher.launchApp',                                                 'device.launcher.checkInstalledApps'                                 ]                         });                 dd.error(function(err) {                                 alert("aa" + JSON.stringify(err));                         });                 function aa(data) {                         alert("call:" + data);                 }                 function openMail(data) {                         dd.device.launcher.launchApp({                                 app : 'cn.mailtech.app', //iOS:应用scheme;Android:应用包名                                 onSuccess : function(data) {                                         //alert(data);                                 },                                 onFail : function(err) {                                         alert("app:" + JSON.stringify(err));                                 }                         });                 }                 dd.ready(function(bridge) {                         dd.runtime.permission.requestAuthCode({                                 corpId : '${ROOT.CORPID}',                                 onSuccess : function(info) {                                     openMail(info);                                         //MobileMeetingAction.getDDUserByCode(info.code, openMail);                                 },                                 onFail : function(err) {                                         alert("hha" + JSON.stringify(err));                                 }                         });                 });         </script> </body> </html> 但是如果我直接不通过action  直接不把页面放在WEB_INF如下却可以,有什么解决办法没 <%@ page language="java" contentType="text/html; charset=UTF-8"         pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ page import="com.hbglobal.ding.auth.AuthHelper,           org.apache.commons.lang.StringUtils,java.net.URLEncoder,           java.io.UnsupportedEncodingException,com.hbglobal.listener.DingDingListener,           net.sf.json.JSONObject,com.hbglobal.ding.po.Env" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>openCoreMail</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <%                 String url=request.getRequestURL().toString();                 String querString=request.getQueryString();                 System.out.println(url+":"+querString);                 if(!StringUtils.isEmpty(querString)&&(!querString.equals("null"))){                         try {                                 querString=URLEncoder.encode(querString, "UTF-8");                         } catch (UnsupportedEncodingException e) {                                 e.printStackTrace();                         }                 }else{                         querString=null;                 }                 String result=AuthHelper.getConfig(url,querString);                         JSONObject  jobj=JSONObject.fromObject(result);                 System.out.println(result);                 String SIGNATURE= jobj.getString("signature");                 String NONCESTR=jobj.getString("nonceStr");                 String TIMESTAMP= jobj.getString("timeStamp");                 String CORPID= Env.CORP_ID; %>         <a href="javaScript:openMail()">启动范文</a>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/js/dingtalk.js"></script>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/dwr/engine.js"></script>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/dwr/util.js"></script>         <script type="text/javascript"                 src="${pageContext.request.contextPath}/dwr/interface/MobileMeetingAction.js"></script>         <script src='${pageContext.request.contextPath}/js/jquery-1.11.3.js'></script>         <script                 src='${pageContext.request.contextPath}/js/jquery-migrate-1.2.1.min.js'></script>         <script type="text/javascript">                    $(function(){                         dd.config({                                 agentId : '9868138',                                 corpId : '<%=CORPID%>',                                 timeStamp : '<%=TIMESTAMP%>',                                 nonceStr : '<%=NONCESTR%>',                                 signature : '<%=SIGNATURE%>',                                 jsApiList : [ 'device.notification.alert',                                                 'device.notification.confirm',                                                 'runtime.permission.requestAuthCode',                                                 'runtime.permission.requestJsApis',                                                 'device.launcher.launchApp',                                                 'device.launcher.checkInstalledApps'                                 ]                         });                         });                 function aa(data) {                         alert("call:" + data);                 }                 function openMail(data) {                         dd.device.launcher.launchApp({                                 apps :'cn.mailtech.app' , //iOS:应用scheme;Android:应用包名                                 onSuccess : function(data) {                                         alert(data);                                 },                                 onFail : function(err) {                                         alert("app:" + JSON.stringify(err));                                 }                         });                 }                 dd.ready(function() {                         dd.runtime.permission.requestAuthCode({                                 corpId : '<%=CORPID%>',                                 onSuccess : function(info) {                                         //MobileMeetingAction.getDDUserByCode(info.code, openMail);                                 },                                 onFail : function(err) {                                         alert("hha" + JSON.stringify(err));                                 }                         });                 });                 dd.error(function(err) {                                 alert("aa" + JSON.stringify(err));                         });         </script> </body> </html>

老李归来 2019-12-02 01:38:00 0 浏览量 回答数 0

问题

在 Node 中使用 PhoneGap Build API 包? 400 报错

爱吃鱼的程序员 2020-05-31 00:23:27 0 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 云栖号物联网 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 云栖号弹性计算 阿里云云栖号 云栖号案例 云栖号直播