当前位置: 首页 > Web前端 > JavaScript

快速理解JavaScript的跨域

时间:2023-03-27 14:02:21 JavaScript

浏览器有一个重要的安全策略,就是同源策略,用来限制不同源之间的资源交互。它可以帮助阻止一些恶意访问并减少可能的攻击媒介。让我们看一个与URLhttp://chat.example.com/u1/arts1/101011.html的来源进行比较的示例。URL结果的原因是http://chat.example.com/u2/arts1/101012.html同源路径不同http://chat.example.com/u1/arts2/101013.html一样-origin路径不同https://chat.example.com/u2/arts2/101014.html失败协议不同http://chat.example.com:88/u1/arts1/101015.html失败端口是不同(http://默认端口80)http://news.example.com/u3/arts4/101017.html失败主机不同所以默认使用XMLHttpRequest的Ajax通信不能访问自己以外的域、协议和端口。但浏览器也需要具备跨源合法访问的能力。图片检测图片检测是最早使用标签实现跨域通信的技术之一。任何页面都可以跨域加载图片而不用担心限制,所以这也是在线广告跟踪的主要方式。图像可以动态创建,然后在通过它们的onload和onerror事件处理程序收到响应时得到通知。这种动态创建图像的技术经常用于图像ping。图像检测是一种简单的、跨域的、与服务器的单向通信。数据通过querystring发送,response可以随时设置,但通常是位图图片或者值为204的状态码。浏览器通过图片检测获取不到任何数据,但是可以通过监听onload和onerror事件知道何时可以收到响应。让我们看下面的例子:.com/test?name=Manoa";此示例创建一个新的Image实例,然后将相同的函数添加到onload和onerror事件。这确保了当请求完成时,您会收到通知是否成功。请求在设置src属性后开始,此示例向服务器发送一个名称值。图像探测经常用于跟踪用户在页面上的点击或动态显示广告。当然,图片检测的缺点是只能发送GET请求,无法获取服务器响应的内容。这就是为什么只能使用探针来实现浏览器和服务器之间的单向通信。JSONPJSONP(带填充的JSON)是JSON的变体。用于解决浏览器的跨域问题。需要动态创建一个元素指定了一个onerror事件处理程序,但它还没有被任何浏览器实现。为此,开发人员经常使用计数器来决定是否放弃等待响应。这种方法并不准确,毕竟不同用户的网络连接速度和带宽是不同的。在CORS出现之前,实现跨域Ajax通信有点麻烦。开发人员需要依赖DOM功能才能执行跨源请求,发送某些类型的请求而不使用XMLHttpRequest对象。虽然CORS现在得到广泛支持,但这些技术仍然具有相关性,因为它们不需要修改服务器。跨域资源共享在CORS出现之前,实现跨域Ajax通信是一件比较麻烦的事情。开发人员需要依赖DOM特性才能执行跨源请求,发送某些类型的请求而不使用XMLHttpRequest。CORS跨域出现后,更方便了,但并不代表上面介绍的这些技术就落伍了,因为它们不需要修改服务,还有使用场景。下面介绍CORS。跨源资源共享(CORS,Cross-OriginResourceSharing)是一种基于HTTP头的机制,通过允许服务器自定义HTTP头,浏览器可以与服务器进行跨源通信。为了安全起见,浏览器限制在脚本中进行的跨源HTTP请求。例如,XMLHttpRequest和FetchAPI遵循同源策略。这意味着使用这些API的Web应用程序只能从加载应用程序的同一域请求HTTP资源,而CORS是HTTP的一部分,它允许服务器指定哪些主机可以从该服务器加载资源,因此响应CORS响应标题应包含在消息中。简单请求不触发CORS预检请求的请求称为“简单请求”。“简单请求”的请求方式为GET、HEAD或POST,头部字段主要是以下字段的集合:AcceptAccept-LanguageContent-LanguageContent-Type:onlytext/plain,multipart/form-dataandapplication/x-www-form-urlencoded三者之一。如果没有自定义标头,则发送请求时会附带一个额外的Origin标头,其中包含发送请求的页面来源,以便服务器为其提供响应。这是一个Origin标头的示例:Origin:http://www.example.com如果服务器决定响应请求,它应该发送包含相同来源的Access-Control-Allow-Origin标头;或者如果资源是公共的,则包含“*”。例如:Access-Control-Allow-Origin:http://www.example.com如果没有这个header,或者有但是source不匹配,就代表浏览器请求不会被响应。否则,服务器处理请求。请注意,请求和响应均不包含cookie信息。现代浏览器通过XMLHttpRequest对象原生支持CORS。当尝试访问来自不同来源的资源时,会自动触发此行为。要向不同域上的源发送请求,请使用标准XMLHttpRequest对象并将绝对URL传递给open()方法,例如:letxhr=newXMLHttpRequest();xhr.onreadystatechange=function(){if(xhr.readyState==4){if((xhr.status>=200&&xhr.status<300)||xhr.status==304){console.log(xhr.响应文本);}else{console.log("请求失败:"+xhr.status);}}};xhr.open("get","http://www.examplecom/page/",true);xhr.发送(空);跨域XMLHttpRequest对象允许访问status和statusText属性,这也允许同步请求。出于安全原因,跨源XMLHttpRequest对象还施加了一些额外的限制。不能使用setRequestHeader()设置自定义标头。无法发送和接收Cookie。getAllResponseHeaders()方法总是返回一个空字符串。因为同域和跨域请求使用同一个接口,所以访问本地资源时最好使用相对URL,访问远程资源时最好使用绝对URL。这样可以更清晰地区分使用场景,同时避免访问本地资源时出现header或cookie信息访问受限的问题。预检请求CORS是预检请求的服务器身份验证机制,允许使用自定义标头、GET和POST以外的方法以及不同的请求正文内容类型。当要发送涉及上述高级选项之一的请求时,首先向服务器发送“预检”请求。此请求使用OPTIONS方法发送,并包含以下标头。来源:与简单请求相同。Access-Control-Request-Method:请求你要使用的方法。Access-Control-Request-Headers:(可选)要使用的自定义标头的逗号分隔列表。以下是一个假设的包含自定义NCZ标头的POST请求:来源:http://www.example.comAccess-Control-Request-Method:POSTAccess-Control-Request-Headers:NCZ发送此请求后,服务器可以判断是否允许此类请求。服务器通过在响应中发送以下标头将此信息传达给浏览器。Access-Control-Allow-Origin:与简单请求相同。Access-Control-Allow-Methods:允许的方法(逗号分隔列表)。Access-Control-Allow-Headers:服务器允许的标头(逗号分隔列表)。Access-Control-Max-Age:缓存预检请求的秒数。例如:Access-Control-Allow-Origin:http://www.example.comAccess-Control-Allow-Methods:POST,GETAccess-Control-Allow-Headers:NCZAccess-Control-Max-Age:1728000预检请求后returns,结果将被缓存一段由响应指定的时间。换句话说,只有第一次发送这种类型的请求时,才会发送额外的HTTP请求。使用“preflightrequest”可以避免跨域请求对服务器端用户数据的意外影响。凭据请求默认情况下,跨源请求不提供凭据(cookie、HTTP身份验证和客户端SSL证书)。您可以通过将withCredentials属性设置为true来指示请求发送凭据。如果服务器允许带有凭据的请求,则可以在响应中包含以下HTTP标头:Access-Control-Allow-Credentials:true如果发送凭据请求并且服务器返回没??有此标头的响应,则浏览器不会响应交给JavaScript(responseText为空字符串,status为0,onerror()被调用)。请注意,服务器也可以发送此HTTP标头以响应预检请求,以指示此来源允许发送凭证请求。HTTP响应头字段下面列出了规范定义的响应头字段。Access-Control-Expose-Headers允许访问资源的外部域URI。参数的值是允许的外部域。如果设置为通配符*,则服务器允许来自所有域的请求。访问控制允许来源:<来源>|*Access-Control-Expose-Headers服务器把允许浏览器访问的headers放入白名单,浏览器中的XMLHttpRequest可以访问X-My-Custom-Header和X-Another-Custom-Header.Access-Control-Expose-Headers:X-My-Custom-Header,X-Another-Custom-HeaderAccess-Control-Max-Age指定可以缓存预检请求结果的秒数。Access-Control-Max-Age:Access-Control-Allow-Credentials指定当浏览器的凭据设置为true时是否允许浏览器读取响应的内容。当用于对预检请求的响应时,它指定实际请求是否可以使用凭据。Access-Control-Allow-Credentials:true注意:简单的GET请求不会被预检;如果该字段不包含在对此类请求的响应中,则该响应将被忽略,浏览器将不会向页面返回相应的内容。Access-Control-Allow-Methods标头字段用于响应预检请求。指示实际请求允许的HTTP方法。Access-Control-Allow-Methods:[,]*Access-Control-Allow-Headers头字段用于预检请求响应。它规定了实际请求中允许携带的头字段。Access-Control-Allow-Headers:[,]*HTTP请求头域下面列出了规范定义的可以用来发起跨域请求的头域。注意:这些标头字段不需要手动设置。使用XMLHttpRequest时自动设置。Origin表示预检请求或实际请求的来源(协议、域和端口)。Origin:origin参数的值为源服务器URI。它不包含任何路径信息,仅包含服务器名称。注意:Origin标头字段始终在所有访问控制请求中发送。Access-Control-Request-Method用于预检请求。它的作用是告诉服务器实际请求使用的HTTP方法。Access-Control-Request-Method:Access-Control-Request-Headers用于预检请求。它的作用是告诉服务器实际请求携带的头字段。Access-Control-Request-Headers:[,]*概要XMLHttpRequest不允许访问其他域名、协议和端口的资源。源政策造成的。如果要跨域访问,需要使用跨域资源共享方案,XMLHttpRequest原生支持CORS。Imagedetection和JSONP是另外两种跨域通信技术,但是相对于CORS,它们都不是很可靠。更多内容请关注公众号《海人的故事》