问题概要
我从域 A 将 PDF.js 加载到 iframe 中,并以文件作为参数(服务器的完整路径,这将返回 pdf 文档)。PDF.js 将向域 B 的服务器创建一个请求,扩展名为origin: domain A. 域 B 的服务器返回带有 header 的 pdf 文档Access-Control-Allow-Origin: domain A,到目前为止一切顺利。
在我的网络选项卡中,我看到对服务器的请求,该请求返回 200 状态 OK,但 PDF.js 抛出错误Unexpected server response (0) while retrieving PDF <url>。
问题是,这里发生了什么,CORS 似乎没问题,但我无法从 PDF.js 获得更多信息,真正的原因是 PDF 无法加载。有没有人遇到过同样的情况?
问题解决
跨域Ajax与跨源资源共享
几年前,Web 开发人员正在用头撞 Ajax 的第一堵墙:同源策略。虽然我们惊叹于跨浏览器支持所带来的巨大进步XMLHttpRequest对象,我们很快就抱怨没有办法从 JavaScript 向不同的域发出请求。每个人都在自己的网站上设置代理,这是一系列新的开放重定向问题的开始,作为绕过限制的一种方法。尽管开发人员正在使用服务器端代理以及其他技术来解决此限制,但社区对允许本机跨域 Ajax 请求的强烈抗议。许多人没有意识到,几乎所有浏览器(Internet Explorer 8+、Firefox 3.5+、Safari 4+ 和 Chrome)目前都通过称为跨源资源共享的协议支持跨域 Ajax。
跨域资源共享 (CORS)
跨源资源共享(CORS) 是 W3C 工作草案,定义了跨源访问源时浏览器和服务器必须如何通信。CORS 背后的基本思想是使用自定义 HTTP 标头,让浏览器和服务器充分了解彼此,以确定请求或响应应该成功还是失败。
对于一个简单的请求,即使用 GET 或 POST 且不带自定义标头且正文为 的请求text/plain,该请求会使用名为 的额外标头发送Origin。标Origin头包含请求页面的来源(协议、域名和端口),以便服务器可以轻松确定是否应该提供响应。示例Origin标头可能如下所示:
Origin: https://humanwhocodes.com
如果服务器决定允许该请求,它会发送一个Access-Control-Allow-Origin标头,回显与发送的相同来源或“*”(如果它是公共资源)。例如:
Access-Control-Allow-Origin: https://humanwhocodes.com
如果此标头丢失,或者来源不匹配,则浏览器将不允许该请求。如果一切顺利,浏览器就会处理该请求。请注意,请求和响应都不包含 cookie 信息。
前面提到的所有浏览器都支持这些简单的请求。Firefox 3.5+、Safari 4+ 和 Chrome 都支持通过该XMLHttpRequest对象使用。当尝试打开不同来源的资源时,此行为会自动触发,无需任何额外代码。例如:
var xhr = new XMLHttpRequest(); xhr.open("get", "https://humanwhocodes.com/some_resource/", true); xhr.onload = function(){//instead of onreadystatechange //do something }; xhr.send(null);
要在 Internet Explorer 8 中执行相同的操作,您需要以相同的方式使用该XDomainRequest对象:
var xdr = new XDomainRequest(); xdr.open("get", " xdr.onload = function(){ //do something }; xdr.send();
Mozilla 团队在有关 CORS 的帖子中建议您应该检查该withCredentials属性是否存在,以确定浏览器是否通过 XHR 支持 CORS。然后,您可以结合该XDomainRequest对象的存在来覆盖所有浏览器:
function createCORSRequest(method, url){ var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr){ xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined"){ xhr = new XDomainRequest(); xhr.open(method, url); } else { xhr = null; } return xhr; } var request = createCORSRequest("get", "https://humanwhocodes.com/"); if (request){ request.onload = function(){ //do something with request.responseText }; request.send(); }
Firefox、Safari 和 Chrome 中的对象XMLHttpRequest与 IE 对象具有足够相似的接口XDomainRequest,因此该模式工作得相当好。常见的接口属性/方法有:
abort()– 用于停止已经在进行的请求。
onerror– 使用而不是onreadystatechange检测错误。
onload– 使用而不是onreadystatechange检测成功。
responseText– 用于获取响应内容。
send()– 用于发送请求。
预检请求
CORS 允许通过称为预检请求的透明服务器验证机制使用自定义标头、GET 或 POST 以外的方法以及不同的正文内容类型。当您尝试使用高级选项之一发出请求时,系统会向服务器发出“预检”请求。此请求使用 OPTIONS 方法并发送以下标头:
Origin– 与简单请求相同。
Access-Control-Request-Method– 请求想要使用的方法。
Access-Control-Request-Headers– (可选)正在使用的自定义标头的逗号分隔列表。
假设一个带有名为 的自定义标头的 POST 请求的示例NCZ:
Origin: https://humanwhocodes.com Access-Control-Request-Method: POST Access-Control-Request-Headers: NCZ
文章来源地址https://www.toymoban.com/diary/js/293.html
在此请求期间,服务器可以确定是否允许此类请求。服务器通过在响应中发送以下标头将此信息传达给浏览器:
Access-Control-Allow-Origin– 与简单请求相同。
Access-Control-Allow-Methods– 允许的方法的逗号分隔列表。
Access-Control-Allow-Headers– 服务器允许的标头的逗号分隔列表。
Access-Control-Max-Age– 此预检请求应缓存的时间(以秒为单位)。
例子:
Access-Control-Allow-Origin: https://humanwhocodes.com Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: NCZ Access-Control-Max-Age: 1728000
一旦发出预检请求,结果将被缓存响应中指定的时间段;您只会在第一次发出此类请求时产生额外 HTTP 请求的费用。
Firefox 3.5+、Safari 4+ 和 Chrome 均支持预检请求;Internet Explorer 8 没有。
凭证请求
默认情况下,跨源请求不提供凭据(cookie、HTTP 身份验证和客户端 SSL 证书)。您可以通过将该属性设置为 true 来指定请求应发送凭据withCredentials。如果服务器允许凭据请求,则它会使用以下 HTTP 标头进行响应:
Access-Control-Allow-Credentials: true
如果发送了凭据请求并且此标头未作为响应的一部分发送,则浏览器不会将响应传递给 JavaScript(responseText是空字符串,status为 0,并且onerror()被调用)。请注意,服务器还可以发送此 HTTP 标头作为预检响应的一部分,以指示允许源发送凭证请求。
Internet Explorer 8 不支持该withCredentials属性;Firefox 3.5、Safari 4 和 Chrome 都支持它。
结论
现代 Web 浏览器对跨域 Ajax 提供了大量可靠的支持,但大多数开发人员仍然没有意识到这种强大的功能。使用时只需要一点额外的 JavaScript 工作和一点额外的服务器端工作即可确保发送正确的标头。IE8 的实现在允许高级请求和凭据请求方面落后于其他版本,但希望对 CORS 的支持将继续改进。文章来源:https://www.toymoban.com/diary/js/293.html
到此这篇关于PDF.js CORS 问题的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!