• 关于

    选择器使用细节

    的搜索结果

问题

个人对云浏览器的建议

zhouzihui0519 2019-12-01 20:05:45 4626 浏览量 回答数 2

问题

【教程免费下载】Unity虚拟现实开发实战

玄学酱 2019-12-01 22:07:47 1731 浏览量 回答数 1

回答

如果我对您的理解正确,则可以在python中使用任何Web框架。例如,您可以使用Flask(我使用并且喜欢)。在python网络框架中,Django也是一个流行的选择。但是,您不应仅局限于这两个。有很多在那里。只是谷歌为他们。 客户端的实现取决于客户端与服务器之间将进行哪种通信-我在这里没有足够的细节。我只知道它是单向的。 客户端可以是访问以Flask编写的Web应用程序的浏览器,其中用户仅向服务器发送POST请求。但是,即使在这种情况下,通信也将是双向的(客户端需要打开页面,这意味着服务器将请求发送回客户端),这违反了您的初始要求。 然后它可以是用python编写的特定客户端,它通过http / https向您的服务器发送一些特定请求。例如,您的客户端可以使用requests包发送HTTP请求。

祖安文状元 2020-02-21 17:29:24 0 浏览量 回答数 0

阿里云试用中心,为您提供0门槛上云实践机会!

0元试用32+款产品,最高免费12个月!拨打95187-1,咨询专业上云建议!

问题

如何选择一款web漏洞扫描器

elinks 2019-12-01 21:15:22 7018 浏览量 回答数 0

回答

文件传输协议(File Transfer Protocol, FTP)FTP是用于在网络上进行文件传输的一套标准协议。它属于网络协议组的应用层。 FTP是一个8位的客户端-服务器协议,能操作任何类型的文件而不需要进一步处理,就像MIME或Unencode一样。但是,FTP有着极高的延时,这意味着,从开始请求到第一次接收需求数据之间的时间会非常长,并且不时的必需执行一些冗长的登陆进程。 概述 FTP服务一般运行在20和21两个端口。端口20用于在客户端和服务器之间传输数据流,而端口21用于传输控制流,并且是命令通向ftp服务器的进口。当数据通过数据流传输时,控制流处于空闲状态。而当控制流空闲很长时间后,客户端的防火墙会将其会话置为超时,这样当大量数据通过防火墙时,会产生一些问题。此时,虽然文件可以成功的传输,但因为控制会话会被防火墙断开,传输会产生一些错误。 FTP实现的目标: 促进文件的共享(计算机程序或数据) 鼓励间接或者隐式的使用远程计算机 向用户屏蔽不同主机中各种文件存储系统的细节 可靠和高效的传输数据 缺点: 密码和文件内容都使用明文传输,可能产生不希望发生的窃听。 因为必需开放一个随机的端口以建立连接,当防火墙存在时,客户端很难过滤处于主动模式下的FTP流量。这个问题通过使用被动模式的FTP得到了很大解决。 服务器可能会被告知连接一个第三方计算机的保留端口。 FTP虽然可以被终端用户直接使用,但是它是设计成被FTP客户端程序所控制。 运行FTP服务的许多站点都开放匿名服务,在这种设置下,用户不需要帐号就可以登录服务器,默认情况下,匿名用户的用户名是:“anonymous”。这个帐号不需要密码,虽然通常要求输入用户的邮件地址作为认证密码,但这只是一些细节或者此邮件地址根本不被确定,而是依赖于FTP服务器的配置情况。 [编辑] 主动和被动模式 FTP有两种使用模式:主动和被动。主动模式要求客户端和服务器端同时打开并且监听一个端口以建立连接。在这种情况下,客户端由于安装了防火墙会产生一些问题。所以,创立了被动模式。被动模式只要求服务器端产生一个监听相应端口的进程,这样就可以绕过客户端安装了防火墙的问题。 一个主动模式的FTP连接建立要遵循以下步骤: 客户端打开一个随机的端口(端口号大于1024,在这里,我们称它为x),同时一个FTP进程连接至服务器的21号命令端口。此时,源端口为随机端口x,在客户端,远程端口为21,在服务器。 客户端开始监听端口(x+1),同时向服务器发送一个端口命令(通过服务器的21号命令端口),此命令告诉服务器客户端正在监听的端口号并且已准备好从此端口接收数据。这个端口就是我们所知的数据端口。 服务器打开20号源端口并且建立和客户端数据端口的连接。此时,源端口为20,远程数据端口为(x+1)。 客户端通过本地的数据端口建立一个和服务器20号端口的连接,然后向服务器发送一个应答,告诉服务器它已经建立好了一个连接。 [编辑] FTP和网页浏览器 大多数最新的网页浏览器和文件管理器都能和FTP服务器建立连接。这使得在FTP上通过一个接口就可以操控远程文件,如同操控本地文件一样。这个功能通过给定一个FTP的URL实现,形如ftp://<服务器地址>(例如,ftp://ftp.gimp.org )。是否提供密码是可选择的,如果有密码,则形如ftp://:@。大部分网页浏览器要求使用被动FTP模式,然而并不是所有的FTP服务器都支持被动模式。

蛮大人123 2019-12-02 02:14:34 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: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: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

回答

首先你要搞清楚一个概念,HTML并不是用来写页面样式的,而是用来表示一个网页的基本架构的,样式用CSS来实现HTML5除了提出很炫的新效果以外还加强了语义化结构,其中这个time就是其中之一用来表示时间,并不是想要达到什么可见的效果,而是让网页的代码有条理,让机器——尤其是百度和谷歌的蜘蛛——能够理解你这个网页的意思。HTML5新增的还有article、nav、header、footer.....等等等,其实现实效果都是和div一样没有效果,但是合理使用却能让页面结构更加清晰有逻辑 看来你被“DIV+CSS”这句哄人的话误导了。当年我也被误导了好几年,以前我做网站从头到尾就只有div,直到后来被一位老人家数落了一顿才觉悟,div是不能滥用的,只能用来做整体的布局,细节部分还是要用其他标签,一方面程序可读性和维护性加强,另一方面,可以用下级选择器来写样式,减少了class和id的命名,可以精简网页的结构;而且语义化结构 有条理才能让搜索引擎更加友好

云栖技术 2019-12-02 02:36:57 0 浏览量 回答数 0

问题

如何给项目选择最合适的编程语言?

chaipanpan 2019-12-01 21:04:01 9813 浏览量 回答数 0

回答

JavaScript具有强大的语义,可以遍历数组和类似数组的对象。我将答案分为两部分:真正数组的选项,以及仅是数组之类的东西的选项,例如arguments对象,其他可迭代对象(ES2015 +),DOM集合,等等。 我会很快注意到,您现在可以通过将ES2015转换为ES5 ,甚至在ES5引擎上使用ES2015选项。搜索“ ES2015 transpiling” /“ ES6 transpiling”以了解更多... 好吧,让我们看看我们的选择: 对于实际数组 您目前在ECMAScript 5(“ ES5”)中拥有三个选项,这是目前最广泛支持的版本,在ECMAScript 2015中又添加了两个选项(“ ES2015”,“ ES6”): 使用forEach及相关(ES5 +) 使用一个简单的for循环 正确使用for-in 使用for-of(隐式使用迭代器)(ES2015 +) 明确使用迭代器(ES2015 +) 细节: 1.使用forEach及相关 在任何可以访问ArrayES5(直接或使用polyfills)添加的功能的模糊现代环境(因此,不是IE8)中,都可以使用forEach(spec| MDN): var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); }); forEach接受回调函数,以及(可选)this调用该回调时要使用的值(上面未使用)。依次为数组中的每个条目调用回调,从而跳过稀疏数组中不存在的条目。尽管上面只使用了一个参数,但回调函数使用以下三个参数调用:每个条目的值,该条目的索引以及对要迭代的数组的引用(以防您的函数尚未使用它) )。 除非您支持IE8之类的过时浏览器(截至2016年9月,NetApps在该市场上所占份额刚刚超过4%),forEach否则您可以在没有垫片的情况下在通用网页中愉快地使用。如果您确实需要支持过时的浏览器,forEach则可以轻松进行填充/填充(搜索“ es5 shim”以获得多个选项)。 forEach 这样做的好处是您不必在包含范围中声明索引和值变量,因为它们是作为迭代函数的参数提供的,因此可以很好地将作用域限定为该迭代。 如果您担心为每个数组条目进行函数调用的运行时成本,请不必担心;细节。 此外,forEach它是“遍历所有对象”功能,但是ES5定义了其他几个有用的“遍历数组并做事”功能,包括: every(在第一次返回回调false或出现错误时停止循环) some(在第一次返回回调true或发生错误时停止循环) filter(创建一个新数组,其中包含过滤器函数返回的元素,true并省略其返回的元素false) map (根据回调返回的值创建一个新数组) reduce (通过重复调用回调并传入先前的值来建立值;有关详细信息,请参见规范;对汇总数组内容和许多其他内容很有用) reduceRight(如reduce,但按降序而不是升序工作) 2.使用一个简单的for循环 有时,旧方法是最好的: var index; var a = ["a", "b", "c"]; for (index = 0; index < a.length; ++index) { console.log(a[index]); } 如果数组的长度将不会在循环过程中改变,它在性能敏感的代码(不可能),一个稍微复杂一点的版本抓住了长度达阵可能是一个很小的有点快: var index, len; var a = ["a", "b", "c"]; for (index = 0, len = a.length; index < len; ++index) { console.log(a[index]); } 和/或倒数: var index; var a = ["a", "b", "c"]; for (index = a.length - 1; index >= 0; --index) { console.log(a[index]); } 但是,使用现代JavaScript引擎,很少需要消耗掉最后的能量。 在ES2015及更高版本中,可以使索引和值变量在for循环本地: let a = ["a", "b", "c"]; for (let index = 0; index < a.length; ++index) { let value = a[index]; console.log(index, value); } //console.log(index); // would cause "ReferenceError: index is not defined" //console.log(value); // would cause "ReferenceError: value is not defined" 而且,当您执行此操作时,不仅会为每个循环迭代创建一个新的闭包,value而且还会index为每个循环迭代重新创建一个闭包,这意味着在循环主体中创建的闭包保留对为该特定迭代创建的index(和value)的引用: let divs = document.querySelectorAll("div"); for (let index = 0; index < divs.length; ++index) { divs[index].addEventListener('click', e => { console.log("Index is: " + index); }); } 如果您有五个div,则单击第一个将获得“索引为:0”,如果单击最后一个则将为“索引为:4”。如果您使用而不是则无法使用。varlet 3. 正确使用for-in 你会得到别人告诉你使用for-in,但是这不是for-in对。for-in遍历对象的可枚举属性,而不是数组的索引。甚至在ES2015(ES6)中也不保证顺序。ES2015 +不定义为对象属性(通过[[OwnPropertyKeys]],[[Enumerate]]以及使用他们喜欢的东西Object.getOwnPropertyKeys),但它并没有定义for-in将遵循这个顺序。(其他答案的详细信息。) for-in数组上唯一真正的用例是: 这是一个稀疏的数组,里面有巨大的空隙,或者 您正在使用非元素属性,并且希望将它们包括在循环中 仅查看第一个示例:for-in如果使用适当的保护措施,则可以用来访问那些备用阵列元素: // a is a sparse array var key; var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (key in a) { if (a.hasOwnProperty(key) && // These checks are /^0$|^[1-9]\d*$/.test(key) && // explained key <= 4294967294 // below ) { console.log(a[key]); } } 请注意以下三个检查: 该对象具有该名称的自身属性(不是从其原型继承的属性),并且 该键是所有十进制数字(例如,正常的字符串形式,而不是科学计数法),并且 该键的值在被强制为数字时为<= 2 ^ 32-2(即4,294,967,294)。这个数字从哪里来?它是规范中数组索引定义的一部分。其他数字(非整数,负数,大于2 ^ 32-2的数字)不是数组索引。它的2 ^ 32的理由- 2是使得大于2 ^ 32下一个最大的索引值- 1,这是一个数组的最大值length可以有。(例如,数组的长度适合于32位无符号整数。)(向RobG表示支持,在我的博客文章的评论中指出我先前的测试不太正确。) 当然,您不会在内联代码中执行此操作。您将编写一个实用程序函数。也许: 4.使用for-of(隐式使用迭代器)(ES2015 +) ES2015将迭代器添加到JavaScript。使用迭代器最简单的方法是new for-of语句。看起来像这样: const a = ["a", "b", "c"]; for (const val of a) { console.log(val); } 在幕后,它从数组中获取一个迭代器并循环遍历,从而从中获取值。这没有使用for-inhas 的问题,因为它使用了由对象(数组)定义的迭代器,并且数组定义了其迭代器遍历其条目(而不是其属性)。与for-inES5 不同,访问条目的顺序是其索引的数字顺序。 5.明确使用迭代器(ES2015 +) 有时,您可能想显式使用迭代器。您也可以这样做,尽管它比笨拙得多for-of。看起来像这样: const a = ["a", "b", "c"]; const it = a.values(); let entry; while (!(entry = it.next()).done) { console.log(entry.value); } 迭代器是与规范中的迭代器定义匹配的对象。每次调用时,其next方法都会返回一个新的结果对象。结果对象具有属性,done告诉我们是否完成操作,以及一个value具有该迭代值的属性。(done如果是false,value则为可选,如果是,则为可选undefined。) 的含义value取决于迭代器;数组至少支持三个返回迭代器的函数: values():这是我上面使用的那个。它返回迭代,其中每个value是用于该迭代阵列条目("a","b",和"c"在实施例更早)。 keys():返回一个迭代器,每个迭代器value都是该迭代的关键(因此,对于我们a上面的代码,将是"0",然后是"1",然后是"2")。 entries():返回一个迭代器,其中每个迭代器value都是[key, value]该迭代形式的数组。 对于类似数组的对象 除了真正的数组之外,还有一些类数组对象,它们具有一个length或多个具有数字名称的属性:NodeList实例,arguments对象等。我们如何遍历它们的内容? 对数组使用上面的任何选项 上面的至少一些(可能是大多数甚至全部)数组方法经常同样适用于类似数组的对象: 使用forEach及相关(ES5 +) 上的各种功能Array.prototype是“有意通用的”,通常可以通过Function#call或在类似数组的对象上使用Function#apply。(在此答案的末尾,请参阅警告,以了解主机提供的对象,但这是一个罕见的问题。) 假设您要forEach在Node的childNodes属性上使用。您可以这样做: Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with `child` }); 如果要执行很多操作,则可能需要将函数引用的副本复制到变量中以供重用,例如: // (This is all presumably in some scoping function) var forEach = Array.prototype.forEach; // Then later... forEach.call(node.childNodes, function(child) { // Do something with `child` }); 使用一个简单的for循环 显然,一个简单的for循环适用于类似数组的对象。 正确使用for-in for-in具有与数组相同的保护措施,也应与类似数组的对象一起使用;上面#1中由主机提供的对象的警告可能适用。 使用for-of(隐式使用迭代器)(ES2015 +) for-of将使用对象提供的迭代器(如果有);我们将不得不看一下它如何与各种类似数组的对象一起运行,尤其是主机提供的对象。例如,NodeListfrom 的规范querySelectorAll已更新以支持迭代。HTMLCollectionfrom 的规格getElementsByTagName不是。 明确使用迭代器(ES2015 +) 参见#4,我们必须看看迭代器如何发挥作用。 创建一个真实的数组 其他时候,您可能希望将类似数组的对象转换为真正的数组。做到这一点非常容易: 使用slice数组的方法 我们可以使用slice数组的方法,就像上面提到的其他方法一样,它是“故意通用的”,因此可以与类似数组的对象一起使用,如下所示: var trueArray = Array.prototype.slice.call(arrayLikeObject); 因此,例如,如果我们要将a NodeList转换为真实数组,则可以执行以下操作: var divs = Array.prototype.slice.call(document.querySelectorAll("div")); 请参阅下面的警告,了解主机提供的对象。特别要注意的是,这将在IE8及更早版本中失败,这不允许您this像这样使用主机提供的对象。 使用传播语法(...) 还可以将ES2015的扩展语法与支持此功能的JavaScript引擎一起使用: var trueArray = [...iterableObject]; 因此,例如,如果我们想将a NodeList转换为真正的数组,使用扩展语法,这将变得非常简洁: var divs = [...document.querySelectorAll("div")]; 使用Array.from (规格) | (MDN) Array.from(ES2015 +,但很容易填充),从类似数组的对象创建数组,可以选择先将条目通过映射函数传递。所以: var divs = Array.from(document.querySelectorAll("div")); 或者,如果您想获取具有给定类的元素的标记名称的数组,则可以使用映射函数: // Arrow function (ES2015): var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName); // Standard function (since `Array.from` can be shimmed): var divs = Array.from(document.querySelectorAll(".some-class"), function(element) { return element.tagName; }); 警告主机提供的对象 如果您将Array.prototype函数与主机提供的类似数组的对象一起使用(DOM列表和浏览器而非JavaScript引擎提供的其他内容),则需要确保在目标环境中进行测试,以确保主机提供的对象行为正常。大多数(现在)确实表现正常,但是测试很重要。原因是Array.prototype您可能要使用的大多数方法都依赖于主机提供的对象,该对象为抽象[[HasProperty]]操作提供了诚实的答案。在撰写本文时,浏览器在这方面做得很好,但是5.1规范确实允许由主机提供的对象可能不诚实。在§8.6.2中,该部分开头附近的大表下方的几段中),其中表示: 除非另有说明,否则宿主对象可以以任何方式实现这些内部方法。例如,一种可能性是,[[Get]]和[[Put]]对特定宿主对象确实读取与存储的属性值但[[HasProperty]]总是产生假。 (我在ES2015规范中找不到等效的用法,但情况肯定仍然如此。)同样,在撰写本文时,现代浏览器中的主机提供的类似数组的对象(NodeList例如,实例)确实可以处理[[HasProperty]]正确,但是测试很重要。) 问题来源于stack overflow

保持可爱mmm 2020-01-08 11:20:24 0 浏览量 回答数 0

回答

对于页面加载时间的测试,简单的需求(仅仅是看看请求时间消耗分布)可以通过开发者工具或者Http Watch了解,但如果是想对页面加载进行优化,进行深入了解的(例如:渲染过程中的CPU开销、网络传输时间与客户端渲染时间的分别耗时、世界同类型站点响应排名),那么可以使用dynaTrace AJAX Edition使用并不复杂,启动浏览器,访问一遍希望了解的页面,针对每一个页面,dynaTrace AJAX Edition都会提供如下信息:1)Summary可以选择和各类型的站点进行性能排名PK,例如alexa排名前1000、500、100的站点、新闻站点、购物网站,了解我们站点在这类型网站中的各项性能指标排名,例如默认的和最佳范例比较,可以看到,综合排名来说,案例业务系统算是A级,超越了96%,缓存等级、网络等级、javascript等级都处于A级,服务响应等级处于B级,顺便说下,排名数据是可以在线更新的。也还可以看到各种加载时间指标的排名情况、服务端时间与客户端时间消耗的排名情况、网络消耗时间排名,以及前面所说指标的等级信息:也还可以看到各种加载时间指标的排名情况、服务端时间与客户端时间消耗的排名情况、网络消耗时间排名,以及前面所说指标的等级信息:2)caching可以看到浏览器缓存利用情况,下面的例子里面等级只能算E,并提示102个静态请求其中97个影响了等级排名列表里面可以看到,所有资源都没有使用expires标记这里也需要注意,post类型的请求,浏览器一般不启用本地缓存,对于静态内容,web服务器默认情况下不会开启expires标记的支持3)network从这里可以看到一些有助于减少网络资源开销的信息,例如4XX、5XX的资源请求又例如图片资源过大、css文件和js文件过大过多的问题,如下图在建议进行图片、css、js文件合并,并估算合并后能够因此带来多少的响应性能提升:又例如图片资源过大、css文件和js文件过大过多的问题,如下图在建议进行图片、css、js文件合并,并估算合并后能够因此带来多少的响应性能提升:4)server-side:列出了所有资源的总响应时间、其中服务器部分的时间,并显示了这些资源的体积,超过200ms的用了红色底色标注5)timeline:  时间轴,按照时间轴显示会话过去页面的每个时间点对应的事件,包括CPU占用(可惜不显示指标值)、javascript时间、类型的呈现、网络上的时间消耗、客户端事件信息。例如下面的监控信息里面可以看到,网络的时间消耗主要是HTML资源,如果需要对细节部分浏览的话,用左键可以划出一个放大的区间,把时间线定位到相应的红色部分,就显示了那个时间点网络资源出现消耗的原因,是两个gif例如下面的监控信息里面可以看到,网络的时间消耗主要是HTML资源,如果需要对细节部分浏览的话,用左键可以划出一个放大的区间,把时间线定位到相应的红色部分,就显示了那个时间点网络资源出现消耗的原因,是两个gif同理,对于javascript,占较长时间的部分是浅黄色表示的“load”,双击时间块可以查看其时间消耗详情以及具体的函数代码:同理,对于javascript,占较长时间的部分是浅黄色表示的“load”,双击时间块可以查看其时间消耗详情以及具体的函数代码:对于rendering,看其中的这一段,双击它:对于rendering,看其中的这一段,双击它:可以看到渲染事件的发生情况,了解css表达式带来的性能问题是否严重可以看到渲染事件的发生情况,了解css表达式带来的性能问题是否严重 可以看到渲染事件的发生情况,了解css表达式带来的性能问题是否严重 可以看到渲染事件的发生情况,了解css表达式带来的性能问题是否严重6)KPI's选项卡:各项指标消耗统计  first impression 视觉上的响应时间 , onload 加载消耗的时间 , total load time 完成加载的时间  requests 请求数,XHR XMLHTTPRequest数

小旋风柴进 2019-12-02 02:25:27 0 浏览量 回答数 0

问题

【教程免费下载】Flume日志收集与MapReduce模式

沉默术士 2019-12-01 22:07:57 1285 浏览量 回答数 1

问题

ImageMagick 魔咒:报错

kun坤 2020-06-08 11:10:10 3 浏览量 回答数 1

回答

概述以人工智能、大数据、物联网传感器技术为基础,将先进的多点电容触摸技术,智能化办公教学软件、多媒体网络通信技术、高清平板显示技术等多项技术融合于一体,整合了普通黑板、教学触摸机、电子白板、电脑等设备于一体的智慧型互联黑板。可完成普通黑板书写、电子白板书写、批注、绘画、课件演示、多媒体娱乐,轻松演绎精彩的互动课堂。 应用范围应用于课堂教学、会议记录等,通过物联网传感器技术,在不改变任何使用习惯下(在普通的黑板上,使用普通粉笔、板擦进行内容书写擦除),将普通黑板或白板上书写的轨迹实时数字化,数字化的板书可以连接通过教室内现有的投影机或其他显示设备实时投影放大,也可以在云端、手机端实时同步。 主要特点1、支持视频、音乐、图片、PPT等各类多媒体教学软件。2、基于普通黑板、普通白板等任何书写面,将普通粉笔或白板笔实时数字化,自动生成带原笔迹电子化板书,实时还原老师重要的板书内容,让老师脱离高亮显示屏书写,保护眼睛健康;相比传统的触摸一体机,互联黑板能够将每个老师各自独有的粉笔字体的形态,粗细,圆润,笔锋都一一还原。3、在白板软件中可以同时打开多个文件,打开后文件以模板图标展示在白板上,可以对其进行旋转、缩放、拖拽等手势操作。4、将老师上课最重要的板书、课件、语音实时保存,还原上课的每一步过程,让学生可以随时回看,有针对性的复习,让老师可以回顾课堂的细节,优化上课过程。5、可通过功能按钮选择板书数字化后的颜色,分为蓝色、红色、黑色,方便老师根据上课内容有差别的进行重点显示。 答案来源网络,供参考,希望对您有帮助

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

问题

【云计算的1024种玩法】为小伙伴搭建一个功能丰富的百度贴吧云签到

妙正灰 2019-12-01 21:14:47 3112 浏览量 回答数 5

问题

如何租用服务器,以及一些细节

persistzpf 2019-12-01 19:34:21 1337 浏览量 回答数 1

回答

1.首先需要学习java基础,了解常用的语法(参考Thinking in Java),避免下面的学习一脸懵逼2.假设你已经自学了java,对于常用的语法和技巧已经了然于心。你可以多关注一些优秀的开源产品:dubbo、spring、tomcat。任何一个优秀的开源产品都是经得起挖掘。并且可以根据自己的方向选择学习轨迹。互联网相关可以看看tomcat了解servlet原理和设计理念。2.1.举个例子,你确定看懂了java io。但是你在学习dubbo和tomcat确定能看懂这些基础是如何实践在生产,有哪些编码技巧和性能优化点需要关注的(使用篇)2.2.举个例子,你确定看懂了基础语法,但是对于dubbo、spring中的动态代理、单例、装饰器等用法是否看的明白,是否有计划去深入挖掘设计者的意图,这个时候一些设计上的技巧是可以学到的(设计篇)2.3.举个例子,你确定连spring都看懂了,但是有没有挖掘到DTD和XSD的相关细节,spring在自定义hadler时候如何有效利用XSD。import关键字和ref关键字是如何解决循环依赖问题(延展篇)3.最后你会发现,大多数生产上我们能用到的优秀产品所涉及的技能和设计理念都是千篇一律,而你需要做的仅仅是先通过书籍和博客了解大致的原理,再通过源码的学习汲取优秀的设计理念和实践经验4.最后一点很关键,需要喜欢做好总结和沉淀,东西看多了容易忘,但是能沉淀的都是方法论,是指导你后面走得更快更远的明灯,给个demo:https://my.oschina.net/tryUcatchUfinallyU/blog/266783

项籍 2019-12-02 01:43:09 0 浏览量 回答数 0

回答

您列出了五个主要的CHARACTER SET麻烦案例。 最佳实践 展望未来,最好使用CHARACTER SET utf8mb4和COLLATION utf8mb4_unicode_520_ci。(管道中有更新版本的Unicode排序规则。) utf8mb4是的超集utf8,它处理4字节utf8代码,表情符号和某些中文需要这些代码。 在MySQL之外,“ UTF-8”是指所有大小的编码,因此实际上与MySQL相同utf8mb4,而不是utf8。 在下文中,我将尝试使用这些拼写和大写字母来区分MySQL内部和外部。 您应该做什么概述 将您的编辑器等设置为UTF-8。 HTML表单应以开头 。 将您的字节编码为UTF-8。 建立UTF-8作为客户端中使用的编码。 声明列/表CHARACTER SET utf8mb4(使用进行检查SHOW CREATE TABLE。) 在HTML的开头 存储的例程获取当前的字符集/排序规则。他们可能需要重建。 UTF-8贯穿始终 有关计算机语言的更多详细信息(及其后续部分) 测试数据 使用工具或工具查看数据SELECT是不可信的。太多这样的客户端,尤其是浏览器,试图补偿不正确的编码,并向您显示正确的文本,即使数据库已损坏。因此,选择一个包含非英语文本的表和列,然后执行 SELECT col, HEX(col) FROM tbl WHERE ... 正确存储的UTF-8的十六进制将为 对于空格(任何语言): 20 对于英语: 4x,5x,6x,或者7x 在西欧大部分地区,带重音符号的字母应为 Cxyy 西里尔文,希伯来文和波斯文/阿拉伯文: Dxyy 亚洲大部分地区: Exyyzz 表情符号和一些中文: F0yyzzww 更多细节 出现问题的具体原因和解决方法 截断的文字(Se为Señor): 要存储的字节未编码为utf8mb4。解决这个问题。 另外,在读取过程中检查连接是否为UTF-8。 黑钻石与问号(Se�or对Señor); 存在以下情况之一: 情况1(原始字节不是 UTF-8): 要存储的字节未编码为utf8。解决这个问题。 的连接(或SET NAMES为)INSERT 和所述SELECT不UTF8 / utf8mb4。解决这个问题。 另外,检查数据库中的列是否为CHARACTER SET utf8(或utf8mb4)。 情况2(原始字节为 UTF-8): 的连接(或SET NAMES)SELECT不是utf8 / utf8mb4。解决这个问题。 另外,检查数据库中的列是否为CHARACTER SET utf8(或utf8mb4)。 仅当浏览器设置为时,才会出现黑色菱形 。 问号(常规的,不是黑钻石)(Se?or用于Señor): 要存储的字节未编码为utf8 / utf8mb4。解决这个问题。 数据库中的列不是CHARACTER SET utf8(或utf8mb4)。解决这个问题。(使用SHOW CREATE TABLE。) 另外,在读取过程中检查连接是否为UTF-8。 Mojibake(Señorfor Señor):(此讨论也适用于Double Encoding,它不一定可见。) 要存储的字节需要UTF-8编码。解决这个问题。 当INSERTing和SELECTing文本的连接需要指定utf8或utf8mb4。解决这个问题。 该列需要声明CHARACTER SET utf8(或utf8mb4)。解决这个问题。 HTML应该以开头 。 如果数据看起来正确,但排序不正确,则说明您选择了错误的排序规则,或者没有适合您的排序规则,或者您使用Double Encoding。 通过执行SELECT .. HEX ..上述操作,可以确认双重编码。 é should come back C3A9, but instead shows C383C2A9 The Emoji  should come back F09F91BD, but comes back C3B0C5B8E28098C2BD 也就是说,十六进制的长度大约是它的两倍。这是由于从latin1(或任何其他形式)转换为utf8,然后将这些字节视为latin1并重复转换而引起的。排序(和比较)无法正常进行,因为例如,排序就像字符串是Señor。来源:stack overflow

保持可爱mmm 2020-05-08 09:56:27 0 浏览量 回答数 0

问题

windows2008系统wamp的安装方法

jackyli 2019-12-01 21:33:22 17332 浏览量 回答数 7

问题

Web测试方法

技术小菜鸟 2019-12-01 21:41:32 7022 浏览量 回答数 1

回答

HTTPS基本原理 一、http为什么不安全。 http协议没有任何的加密以及身份验证的机制,非常容易遭遇窃听、劫持、篡改,因此会造成个人隐私泄露,恶意的流量劫持等严重的安全问题。 国外很多网站都支持了全站https,国内方面目前百度已经在年初完成了搜索的全站https,其他大型的网站也在跟进中,百度最先完成全站https的最大原因就是百度作为国内最大的流量入口,劫持也必然是首当其冲的,造成的有形的和无形的损失也就越大。关于流量劫持问题,我在另一篇文章中也有提到,基本上是互联网企业的共同难题,https也是目前公认的比较好的解决方法。但是https也会带来很多性能以及访问速度上的牺牲,很多互联网公司在做大的时候都会遇到这个问题:https成本高,速度又慢,规模小的时候在涉及到登录和交易用上就够了,做大以后遇到信息泄露和劫持,想整体换,代价又很高。 2、https如何保证安全 要解决上面的问题,就要引入加密以及身份验证的机制。 这时我们引入了非对称加密的概念,我们知道非对称加密如果是公钥加密的数据私钥才能解密,所以我只要把公钥发给你,你就可以用这个公钥来加密未来我们进行数据交换的秘钥,发给我时,即使中间的人截取了信息,也无法解密,因为私钥在我这里,只有我才能解密,我拿到你的信息后用私钥解密后拿到加密数据用的对称秘钥,通过这个对称密钥来进行后续的数据加密。除此之外,非对称加密可以很好的管理秘钥,保证每次数据加密的对称密钥都是不相同的。 但是这样似乎还不够,如果中间人在收到我的给你公钥后并没有发给你,而是自己伪造了一个公钥发给你,这是你把对称密钥用这个公钥加密发回经过中间人,他可以用私钥解密并拿到对称密钥,此时他在把此对称密钥用我的公钥加密发回给我,这样中间人就拿到了对称密钥,可以解密传输的数据了。为了解决此问题,我们引入了数字证书的概念。我首先生成公私钥,将公钥提供给相关机构(CA),CA将公钥放入数字证书并将数字证书颁布给我,此时我就不是简单的把公钥给你,而是给你一个数字证书,数字证书中加入了一些数字签名的机制,保证了数字证书一定是我给你的。 所以综合以上三点: 非对称加密算法(公钥和私钥)交换秘钥 + 数字证书验证身份(验证公钥是否是伪造的) + 利用秘钥对称加密算法加密数据 = 安全 3、https协议简介 为什么是协议简介呢。因为https涉及的东西实在太多了,尤其是一些加密算法,非常的复杂,对于这些算法面的东西就不去深入研究了,这部分仅仅是梳理一下一些关于https最基本的原理,为后面分解https的连接建立以及https优化等内容打下理论基础。 3.1 对称加密算法 对称加密是指加密和解密使用相同密钥的加密算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信至关重要。 对称加密又分为两种模式:流加密和分组加密。 流加密是将消息作为位流对待,并且使用数学函数分别作用在每一个位上,使用流加密时,每加密一次,相同的明文位会转换成不同的密文位。流加密使用了密钥流生成器,它生成的位流与明文位进行异或,从而生成密文。现在常用的就是RC4,不过RC4已经不再安全,微软也建议网络尽量不要使用RC4流加密。 分组加密是将消息划分为若干位分组,这些分组随后会通过数学函数进行处理,每次一个分组。假设需要加密发生给对端的消息,并且使用的是64位的分组密码,此时如果消息长度为640位,就会被划分成10个64位的分组,每个分组都用一系列数学公式公式进行处理,最后得到10个加密文本分组。然后,将这条密文消息发送给对端。对端必须拥有相同的分组密码,以相反的顺序对10个密文分组使用前面的算法解密,最终得到明文的消息。比较常用的分组加密算法有DES、3DES、AES。其中DES是比较老的加密算法,现在已经被证明不安全。而3DES是一个过渡的加密算法,相当于在DES基础上进行三重运算来提高安全性,但其本质上还是和DES算法一致。而AES是DES算法的替代算法,是现在最安全的对称加密算法之一。分组加密算法除了算法本身外还存在很多种不同的运算方式,比如ECB、CBC、CFB、OFB、CTR等,这些不同的模式可能只针对特定功能的环境中有效,所以要了解各种不同的模式以及每种模式的用途。这个部分后面的文章中会详细讲。 对称加密算法的优、缺点: 优点:算法公开、计算量小、加密速度快、加密效率高。 缺点:(1)交易双方都使用同样钥匙,安全性得不到保证; (2)每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。 (3)能提供机密性,但是不能提供验证和不可否认性。 3.2 非对称加密算法 在非对称密钥交换算法出现以前,对称加密一个很大的问题就是不知道如何安全生成和保管密钥。非对称密钥交换过程主要就是为了解决这个问题,使得对称密钥的生成和使用更加安全。 密钥交换算法本身非常复杂,密钥交换过程涉及到随机数生成,模指数运算,空白补齐,加密,签名等操作。 常见的密钥交换算法有RSA,ECDHE,DH,DHE等算法。涉及到比较复杂的数学问题,下面就简单介绍下最经典的RSA算法。RSA:算法实现简单,诞生于1977年,历史悠久,经过了长时间的破解测试,安全性高。缺点就是需要比较大的素数也就是质数(目前常用的是2048位)来保证安全强度,很消耗CPU运算资源。RSA是目前唯一一个既能用于密钥交换又能用于证书签名的算法。我觉得RSA可以算是最经典的非对称加密算法了,虽然算法本身都是数学的东西,但是作为最经典的算法,我自己也花了点时间对算法进行了研究,后面会详细介绍。 非对称加密相比对称加密更加安全,但也存在两个明显缺点: 1,CPU计算资源消耗非常大。一次完全TLS握手,密钥交换时的非对称解密计算量占整个握手过程的90%以上。而对称加密的计算量只相当于非对称加密的0.1%,如果应用层数据也使用非对称加解密,性能开销太大,无法承受。 2,非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是2048位,意味着待加密内容不能超过256个字节。 所以公钥加密(极端消耗CPU资源)目前只能用来作密钥交换或者内容签名,不适合用来做应用层传输内容的加解密。 3.3 身份认证 https协议中身份认证的部分是由数字证书来完成的,证书由公钥、证书主体、数字签名等内容组成,在客户端发起SSL请求后,服务端会将数字证书发给客户端,客户端会对证书进行验证(验证查看这张证书是否是伪造的。也就是公钥是否是伪造的),并获取用于秘钥交换的非对称密钥(获取公钥)。 数字证书有两个作用: 1,身份授权。确保浏览器访问的网站是经过CA验证的可信任的网站。 2,分发公钥。每个数字证书都包含了注册者生成的公钥(验证确保是合法的,非伪造的公钥)。在SSL握手时会通过certificate消息传输给客户端。 申请一个受信任的数字证书通常有如下流程: 1,终端实体(可以是一个终端硬件或者网站)生成公私钥和证书请求。 2,RA(证书注册及审核机构)检查实体的合法性。如果个人或者小网站,这一步不是必须的。 3,CA(证书签发机构)签发证书,发送给申请者。 4,证书更新到repository(负责数字证书及CRL内容存储和分发),终端后续从repository更新证书,查询证书状态等。 数字证书验证: 申请者拿到CA的证书并部署在网站服务器端,那浏览器发起握手接收到证书后,如何确认这个证书就是CA签发的呢。怎样避免第三方伪造这个证书。答案就是数字签名(digital signature)。数字签名是证书的防伪标签,目前使用最广泛的SHA-RSA(SHA用于哈希算法,RSA用于非对称加密算法)数字签名的制作和验证过程如下: 1,数字签名的签发。首先是使用哈希函数对待签名内容进行安全哈希,生成消息摘要,然后使用CA自己的私钥对消息摘要进行加密。 2,数字签名的校验。使用CA的公钥解密签名,然后使用相同的签名函数对待签名证书内容进行签名并和服务端数字签名里的签名内容进行比较,如果相同就认为校验成功。 需要注意的是: 1)数字签名签发和校验使用的密钥对是CA自己的公私密钥,跟证书申请者提交的公钥没有关系。 2)数字签名的签发过程跟公钥加密的过程刚好相反,即是用私钥加密,公钥解密。 3)现在大的CA都会有证书链,证书链的好处一是安全,保持根CA的私钥离线使用。第二个好处是方便部署和撤销,即如果证书出现问题,只需要撤销相应级别的证书,根证书依然安全。 4)根CA证书都是自签名,即用自己的公钥和私钥完成了签名的制作和验证。而证书链上的证书签名都是使用上一级证书的密钥对完成签名和验证的。 5)怎样获取根CA和多级CA的密钥对。它们是否可信。当然可信,因为这些厂商跟浏览器和操作系统都有合作,它们的公钥都默认装到了浏览器或者操作系统环境里。 3.4 数据完整性验证 数据传输过程中的完整性使用MAC算法来保证。为了避免网络中传输的数据被非法篡改,SSL利用基于MD5或SHA的MAC算法来保证消息的完整性。 MAC算法是在密钥参与下的数据摘要算法,能将密钥和任意长度的数据转换为固定长度的数据。发送者在密钥的参与下,利用MAC算法计算出消息的MAC值,并将其加在消息之后发送给接收者。接收者利用同样的密钥和MAC算法计算出消息的MAC值,并与接收到的MAC值比较。如果二者相同,则报文没有改变;否则,报文在传输过程中被修改,接收者将丢弃该报文。 由于MD5在实际应用中存在冲突的可能性比较大,所以尽量别采用MD5来验证内容一致性。SHA也不能使用SHA0和SHA1,中国山东大学的王小云教授在2005年就宣布破解了 SHA-1完整版算法。微软和google都已经宣布16年及17年之后不再支持sha1签名证书。MAC算法涉及到很多复杂的数学问题,这里就不多讲细节了。 专题二--【实际抓包分析】 抓包结果: fiddler: wireshark: 可以看到,百度和我们公司一样,也采用以下策略: (1)对于高版本浏览器,如果支持 https,且加解密算法在TLS1.0 以上的,都将所有 http请求重定向到 https请求 (2)对于https请求,则不变。 【以下只解读https请求】 1、TCP三次握手 可以看到,我们访问的是 http://www.baidu.com/ , 在初次建立 三次握手的时候, 用户是去 连接 8080端口的(因为公司办公网做了代理,因此,我们实际和代理机做的三次握手,公司代理机再帮我们去连接百度服务器的80端口) 2、CONNECT 建立 由于公司办公网访问非腾讯域名,会做代理,因此,在进行https访问的时候,我们的电脑需要和公司代理机做 " CONNECT " 连接(关于 " CONNECT " 连接, 可以理解为虽然后续的https请求都是公司代理机和百度服务器进行公私钥连接和对称秘钥通信,但是,有了 " CONNECT " 连接之后,可以认为我们也在直接和百度服务器进行公私钥连接和对称秘钥通信。 ) fiddler抓包结果: CONNECT之后, 后面所有的通信过程,可以看做是我们的机器和百度服务器在直接通信 3、 client hello 整个 Secure Socket Layer只包含了: TLS1.2 Record Layer内容 (1)随机数 在客户端问候中,有四个字节以Unix时间格式记录了客户端的协调世界时间(UTC)。协调世界时间是从1970年1月1日开始到当前时刻所经历的秒数。在这个例子中,0x2516b84b就是协调世界时间。在他后面有28字节的随机数( random_C ),在后面的过程中我们会用到这个随机数。 (2)SID(Session ID) 如果出于某种原因,对话中断,就需要重新握手。为了避免重新握手而造成的访问效率低下,这时候引入了session ID的概念, session ID的思想很简单,就是每一次对话都有一个编号(session ID)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。 因为我们抓包的时候,是几个小时内第一次访问 https://www.baodu.com 首页,因此,这里并没有 Session ID. (稍会儿我们会看到隔了半分钟,第二次抓包就有这个Session ID) session ID是目前所有浏览器都支持的方法,但是它的缺点在于session ID往往只保留在一台服务器上。所以,如果客户端的请求发到另一台服务器,就无法恢复对话。session ticket就是为了解决这个问题而诞生的,目前只有Firefox和Chrome浏览器支持。 (3) 密文族(Cipher Suites): RFC2246中建议了很多中组合,一般写法是"密钥交换算法-对称加密算法-哈希算法,以“TLS_RSA_WITH_AES_256_CBC_SHA”为例: (a) TLS为协议,RSA为密钥交换的算法; (b) AES_256_CBC是对称加密算法(其中256是密钥长度,CBC是分组方式); (c) SHA是哈希的算法。 浏览器支持的加密算法一般会比较多,而服务端会根据自身的业务情况选择比较适合的加密组合发给客户端。(比如综合安全性以及速度、性能等因素) (4) Server_name扩展:( 一般浏览器也支持 SNI(Server Name Indication)) 当我们去访问一个站点时,一定是先通过DNS解析出站点对应的ip地址,通过ip地址来访问站点,由于很多时候一个ip地址是给很多的站点公用,因此如果没有server_name这个字段,server是无法给与客户端相应的数字证书的,Server_name扩展则允许服务器对浏览器的请求授予相对应的证书。 还有一个很好的功能: SNI(Server Name Indication)。这个的功能比较好,为了解决一个服务器使用多个域名和证书的SSL/TLS扩展。一句话简述它的工作原理就是,在连接到服务器建立SSL连接之前先发送要访问站点的域名(Hostname),这样服务器根据这个域名返回一个合适的CA证书。目前,大多数操作系统和浏览器都已经很好地支持SNI扩展,OpenSSL 0.9.8已经内置这一功能,据说新版的nginx也支持SNI。) 4、 服务器回复(包括 Server Hello, Certificate, Certificate Status) 服务器在收到client hello后,会回复三个数据包,下面分别看一下: 1)Server Hello 1、我们得到了服务器的以Unix时间格式记录的UTC和28字节的随机数 (random_S)。 2、Seesion ID,服务端对于session ID一般会有三种选择 (稍会儿我们会看到隔了半分钟,第二次抓包就有这个Session ID) : 1)恢复的session ID:我们之前在client hello里面已经提到,如果client hello里面的session ID在服务端有缓存,服务端会尝试恢复这个session; 2)新的session ID:这里又分两种情况,第一种是client hello里面的session ID是空值,此时服务端会给客户端一个新的session ID,第二种是client hello里面的session ID此服务器并没有找到对应的缓存,此时也会回一个新的session ID给客户端; 3)NULL:服务端不希望此session被恢复,因此session ID为空。 3、我们记得在client hello里面,客户端给出了21种加密族,而在我们所提供的21个加密族中,服务端挑选了“TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256”。 (a) TLS为协议,RSA为密钥交换的算法; (b) AES_256_CBC是对称加密算法(其中256是密钥长度,CBC是分组方式); (c) SHA是哈希的算法。 这就意味着服务端会使用ECDHE-RSA算法进行密钥交换,通过AES_128_GCM对称加密算法来加密数据,利用SHA256哈希算法来确保数据完整性。这是百度综合了安全、性能、访问速度等多方面后选取的加密组合。 2)Certificate 在前面的https原理研究中,我们知道为了安全的将公钥发给客户端,服务端会把公钥放入数字证书中并发给客户端(数字证书可以自签发,但是一般为了保证安全会有一个专门的CA机构签发),所以这个报文就是数字证书,4097 bytes就是证书的长度。 我们打开这个证书,可以看到证书的具体信息,这个具体信息通过抓包报文的方式不是太直观,可以在浏览器上直接看。 (点击 chrome 浏览器 左上方的 绿色 锁型按钮) 3)Server Hello Done 我们抓的包是将 Server Hello Done 和 server key exchage 合并的包: 4)客户端验证证书真伪性 客户端验证证书的合法性,如果验证通过才会进行后续通信,否则根据错误情况不同做出提示和操作,合法性验证包括如下: 证书链的可信性trusted certificate path,方法如前文所述; 证书是否吊销revocation,有两类方式离线CRL与在线OCSP,不同的客户端行为会不同; 有效期expiry date,证书是否在有效时间范围; 域名domain,核查证书域名是否与当前的访问域名匹配,匹配规则后续分析; 5)秘钥交换 这个过程非常复杂,大概总结一下: (1)首先,其利用非对称加密实现身份认证和密钥协商,利用非对称加密,协商好加解密数据的 对称秘钥(外加CA认证,防止中间人窃取 对称秘钥) (2)然后,对称加密算法采用协商的密钥对数据加密,客户端和服务器利用 对称秘钥 进行通信; (3)最后,基于散列函数验证信息的完整性,确保通信数据不会被中间人恶意篡改。 此时客户端已经获取全部的计算协商密钥需要的信息:两个明文随机数random_C和random_S与自己计算产生的Pre-master(由客户端和服务器的 pubkey生成的一串随机数),计算得到协商对称密钥; enc_key=Fuc(random_C, random_S, Pre-Master) 6)生成 session ticket 如果出于某种原因,对话中断,就需要重新握手。为了避免重新握手而造成的访问效率低下,这时候引入了session ID的概念, session ID的思想很简单,就是每一次对话都有一个编号(session ID)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。 因为我们抓包的时候,是几个小时内第一次访问 https://www.baodu.com 首页,因此,这里并没有 Session ID. (稍会儿我们会看到隔了半分钟,第二次抓包就有这个Session ID) session ID是目前所有浏览器都支持的方法,但是它的缺点在于session ID往往只保留在一台服务器上。所以,如果客户端的请求发到另一台服务器,就无法恢复对话。session ticket就是为了解决这个问题而诞生的,目前只有Firefox和Chrome浏览器支持。 后续建立新的https会话,就可以利用 session ID 或者 session Tickets , 对称秘钥可以再次使用,从而免去了 https 公私钥交换、CA认证等等过程,极大地缩短 https 会话连接时间。 7) 利用对称秘钥传输数据 【半分钟后,再次访问百度】: 有这些大的不同: 由于服务器和浏览器缓存了 Session ID 和 Session Tickets,不需要再进行 公钥证书传递,CA认证,生成 对称秘钥等过程,直接利用半分钟前的 对称秘钥 加解密数据进行会话。 1)Client Hello 2)Server Hello

玄学酱 2019-12-02 01:27:08 0 浏览量 回答数 0

回答

  Spring框架推出5.0,其中包含了WebFlux,与过去我们所知的SpringWebMVC的差异是什么?开发者们准备好接受另一套模型了吗?新版Spring的一大特色,就是ReactiveWeb方案的WebFlux,这是用来替代SpringWebMVC的吗?或者,只是终于可以不再基于Servlet容器了?   基于Servlet容器的WebMVC   身为Java开发者,对于Spring框架并不陌生。它最初起源于2002年,是RodJohnson的著作“ExpertOne-on-OneJ2EE设计与开发”中的界面框架。到了2004年,推出Spring1.0,从XML到3.0之后,开始支援JavaConfig设定;进一步地,在2014年时,除了Spring4.0之外,首次发表了SpringBoot,最大的亮点是采用自动组态,令基于Spring的快速开发成为可能。   对Web开发者来说,Spring中的WebMVC框架,也一直随着Spring而成长,然而由于基于Servlet容器,早期被批评测试不易(例如:控制器中包含了ServletAPI)。   不过,从实作Controller介面搭配XML设定,到后来的标注搭配JavaConfig,WebMVC使用越来越便利。如果愿意,也可采用渐进的方式,将基于ServletAPI的Web应用程序,逐步重构为几乎没有ServletAPI的存在(可参考先前专栏文章<筛选框架必要功能>),在程式码层面达到屏壁ServletAPI的效果。   由于不少Java开发者的Web开发经验,都是从Servlet容器中累积起来的,在这个时候,WebMVC框架基于ServletAPI,就会是一项优点。因为,虽然运用WebMVC撰写程式时,可做到不直接面对ServletAPI,然而,也意味着更强烈地受到Spring的约束,有时则是无法在庞杂设定或API中找到对应方案,有时也因为心智模型还是挂在Servlet容器,经验上难以脱离,在搞不出的HttpSession,ServletContext的对应功能时,直接从HttpSession中,ServletContext的下手,毕竟也是个方法。   撰写程式时,就算没用到ServletAPI,WebMVC基于Servlet容器仍是事实,因为,底层还是得借助Servlet容器的功能,例如SpringSecurity,本质上还是基于Servlet容器的过滤器方案。   然而在今日,Servlet被许多开发者视为陈旧,过时技术的象征,或许是因为这样,在JavaEE8宣布推出的这段期间,当我在某些场合谈及Servlet4.0之时,总会听到有人提出「WebFlux可以脱离Servlet了」之类的善心建议。   实现ReactiveStreams的Reactor   WebFlux不依赖Servlet容器是事实,然而,在谈及WebFlux之前,我们必须先知道Reactor专案,它是由Pivotal公司,也就是目前Spring的拥有者推出,实现了ReactiveStreams规范,用来支援Reactive编程的实作品。   既然是实现了ReactiveStreams规范,开发者必然会想到的是RxJava/RxJava2,或者至是Java9的FlowAPI。这也意道着,在能使用WebFlux之前,开发者必须对于ReactiveProgramming典范,有所认识,如果你从未接触过这些玩意儿,可以参考先前专栏。   开发者这时有疑问了,Spring为何不直接基于RxJava2,而是打造专属的ReactiveStreams实作呢?   就技术而言,Reactor是在Java8的基础上开发,并全面拥抱Java8之后的新API,像是Lambda相关介面,新日期与时间API等,这意谓着,专案如果还是基于Java7或更早版本,就无法使用电抗器。   在API层面,RxJava2有着因为历史发展脉络的原因,不得不保留一些令人容易困惑或混淆的模态或操作,而Reactor在这方面,都有着明确的对应API来取代,然而,却也提供与RxJava2(甚至是FlowAPI)间的转换。   另一方面,Reactor较直觉易用,例如最常介绍的Mono与Flux,实现了ReactiveStreams的发布者介绍,并简化了讯息发布,让开发者在许多场合,不用处理Subscriber和Subscription的细节(当然,这些在Reactor也予以实现)。而在SpringWebFlux中,Mono与Flux也是主要的操作对象。想知道如何使用Mono与Flux,可以参考<使用Reactor进行反应式编程>(https://goo.gl/vc2fGc)。   又一个的Web框架?   到了春天5,在Reactor的基础上,新增了WebFlux作为ReactiveWeb方案,我们在许多介绍文件的简单范例,例如<使用Spring5的WebFlux开发反应式Web应用>(https://goo.gl/G5uotZ),就看到当中使用了Flux,Mono来示范,而且,程式码看起来就像是SpringMVC。   这是因为WebFlux提供了基于Java标注的方式,有许多WebMVC中使用的标注,也拿来用于WebFlux之中,让熟悉WebMVC的开发者也容易理解与上手WebFlux,然而,这不过就是新的网络框架吗?   实际上,当然不是如此.WebFlux并非依赖WebMVC,而且它是基于Reactor,本质属于非同步,非阻断,ReactiveProgramming的心智模型,也因此,如果打算将WebFlux运行在Servlet容器之上,必须是支援Servlet3.1以上,因为才有非阻断输入输出的支援,虽然WebFlux的API在某些地方,确实提供了阻断的选项,若单纯只是试着将基于WebMVC的应用程式,改写为套用WebFlux,并不会有任何益处,反而会穷于应付如何在WebFlux实现对应的方案。   例如,SpringSecurity显然就不能用了,毕竟是Spring基于Servlet的安全方案,开发者必须想办法套用SpringSecurityReactive;而且,在储存方案上,也不是直接采用SpringData,而不是SpringData反应等。   就算能套用相关的设定与API,要能获得WebFlux的益处,应用程式中相关的元件,也必须全面检视,重新设计为非阻断,基于ReactiveProgramming方式,这或许才是最困难,麻烦的部份。   除了基于Java标注的方式,让熟悉WebMVC的开发者容易理解之外,WebFlux还提供了基于函数式的设计与组态方式。   实际上,在运用RxJava2/Reactor等ReactiveStreams的实作时,我们也都必须熟悉函数式的思考方式,才能充分掌握,这点在WebFlux并不例外。   可以脱离的Servlet容器了?   Servlet容器是个旧时代的象征,如果能够屏蔽Servlet容器或相关API,许多开发者应应都会很开心,可以少一层抽象,不必使用肥肥的Servlet容器,当然会是使用WebFlux时附带的优点,然而,如果只是为了屏蔽的Servlet,其实,早就有其他技术选择存在。   基于Servlet一路发展过来的WebMVC,虽然目前在某些地方可以安插一些函数式的设计,然而,本质上不变的部分在于,在技术堆叠中所隐含的,仍是一个基于同步,阻断式,命令式的心智模型。如果在这样的堆叠中,开发者老是因为想要实现非同步,非阻断,Reactive,函数式而感到不快,WebFlux也许才会是可考虑的方案,而不单只是用来作为脱离Servlet容器,WebMVC的替代品。   整体而言,WebFlux还算是新技术,也还有待时间验证可行性,如果只是为了想用WebFlux来取代WebMVC,或甚至更小一点的野心,只是想要能脱离Servlet容器,最好在采取行动之前,全面检视一下,确认自身或团队成员是否准备好接受WebFlux的心智模型,或者真的存在着对应的应用场景吧! 原文地址:https://yq.aliyun.com/articles/638706

auto_answer 2019-12-02 01:48:10 0 浏览量 回答数 0

问题

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

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

问题

AMH面板4.1新版本已发布

smyz 2019-12-01 21:28:44 18190 浏览量 回答数 11
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站