CORS原理及详细使用(转载)

本文介绍了CORS(跨域资源共享),它需浏览器和服务器同时支持。CORS分简单请求和非简单请求,前端代码与普通Ajax请求无差异,关键在服务端设置。还介绍了CORS相关字段,如Access-Control-Allow-Methods等。CORS配置简单,兼容性好,优势明显。

CORS:全称"跨域资源共享"(Cross-origin resource sharing)。

CORS需要浏览器和服务器同时支持,才可以实现跨域请求,目前几乎所有浏览器都支持CORS,IE则不能低于IE10。CORS的整个过程都由浏览器自动完成,前端无需做任何设置,跟平时发送ajax请求并无差异。so,实现CORS的关键在于服务器,只要服务器实现CORS接口,就可以实现跨域通信。

请求类型:
CORS分为简单请求和非简单请求(需预检请求)两类

符合以下条件的,为简单请求

请求方式使用下列方法之一:

  • GET
  • HEAD
  • POST

Content-Type 的值仅限于下列三者之一:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

对于简单请求,浏览器会直接发送CORS请求,具体说来就是在header中加入origin请求头字段。同样,在响应头中,返回服务器设置的相关CORS头部字段,Access-Control-Allow-Origin字段为允许跨域请求的源。请求时浏览器在请求头的Origin中说明请求的源,服务器收到后发现允许该源跨域请求,则会成功返回。

非简单请求(预检请求)

使用了下面任一 HTTP 方法:

  • PUT
  • DELETE
  • CONNECT
  • OPTIONS
  • TRACE
  • PATCH

 
Content-Type 的值不属于下列之一:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

当发生符合非简单请求(预检请求)的条件时,浏览器会自动先发送一个options请求,如果发现服务器支持该请求,则会将真正的请求发送到后端,反之,如果浏览器发现服务端并不支持该请求,则会在控制台抛出错误。

前端代码与发送普通Ajax请求没有差异,我们只需在服务端设置即可

以node做服务端为例:

var express = require('express');
var app = express();
var allowCrossDomain = function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3001');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
}
app.use(allowCrossDomain);

接下来,http://localhost:3001下的GET,PUT,POST,DELETE请求,自定义首部字段为Content-Type的非简单请求则会被正常访问,当然,你也可以将Access-control-Allow-Methods和Access-Control-Allow-Headers这两个配置删掉,删掉之后,将仅支持简单请求进行跨域。
--------------------- 

CORS字段介绍:
(1)Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

(2)Access-Control-Allow-Headers

如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

(3)Access-Control-Allow-Credentials

该字段与简单请求时的含义相同。

(4)Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

总结:
总的来说,使用CORS简单请求,非常容易,对于前端来说无需做任何配置,与发送普通ajax请求无异。唯一需要注意的是,需要携带cookie信息时,需要将withCredentials设置为true即可。CORS的配置,完全在后端设置,配置起来也比较容易,目前对于大部分浏览器兼容性也比较好。CORS优势也比较明显,可以实现任何类型的请求,相较于JSONP跨域只能使用get请求来说,也更加便于我们使用。


原文地址:https://blog.youkuaiyun.com/badmoonc/article/details/82706246 

相关链接:AJAX详解-廖雪峰官网 

<think>嗯,我现在需要解决在Vue.js项目中通过iframe使用contentWindow.print()打印PDF时的跨域问题。用户提到使用Ajax请求流并用Blob处理二进制数据生成URL,同时要注意释放资源。首先,我得理清整个流程。 首先,跨域问题通常是由于浏览器的同源策略导致的。如果PDF资源在另一个域,直接通过iframe加载可能会被阻止。所以用户的方法是通过Ajax获取PDF的二进制流,然后用Blob转换成URL,这样应该可以绕过跨域限制,因为Ajax请求可以设置响应类型为blob,而Blob URL是同源的。 接下来,用户提到使用window.URL.createObjectURL(blob)来生成一个临时URL,并把这个URL赋给iframe的src。这样iframe就可以加载这个同源的URL,从而避免跨域问题。不过需要注意的是,生成Blob URL之后,必须在适当的时候释放它,否则可能会内存泄漏。用户示例代码中有使用window.URL.revokeObjectURL(blob),但可能需要确认是否正确执行。 然后,用户想在Vue.js中实现这个功能。Vue.js通常使用axios或fetch进行Ajax请求,所以需要配置responseType为'blob'。例如,在axios中设置responseType: 'blob',这样返回的数据就是Blob对象。然后创建Blob URL,并赋值给iframe的src。接着,在iframe加载完成后调用contentWindow.print()方法触发打印。 但是,可能存在几个问题。首先,跨域请求需要服务器端设置CORS头部,比如Access-Control-Allow-Origin。否则,即使前端使用Ajax获取数据,也可能被服务器拒绝。其次,在生成Blob URL后,如果iframe还没有加载完成就调用print(),可能会失败。所以需要确保在iframe的onload事件中执行打印。此外,在Vue中操作DOM可能需要使用refs来获取iframe元素,或者在mounted生命周期钩子中处理。 另外,用户提到释放资源,应该在打印完成后立即调用revokeObjectURL,但如果在iframe加载后立即释放,可能会导致资源不可用。所以正确的做法是在确保iframe已经加载并打印之后再释放,比如使用setTimeout或者监听iframe的load事件后再执行revoke。 现在,我需要结合用户的引用内容来看。引用[1]和[2]展示了通过Ajax获取二进制流,生成Blob URL,然后通过iframe加载并打印的流程。引用[3]使用axios处理跨域请求,并在iframe的onload事件中调用打印。引用[4]则展示了另一种通过XHR处理响应并写入iframe的方法,但用户可能更倾向于使用Blob URL的方式。 所以,综合这些信息,解决方案应该是:在Vue组件中使用axios发送GET请求,设置responseType为'blob',获取到PDF数据后生成Blob URL,创建一个隐藏的iframe,设置其src为这个URL,监听iframe的load事件,在事件触发后调用contentWindow.print(),并在打印完成后释放URL。 需要注意的是,在Vue中操作DOM元素时,最好使用refs来引用iframe,避免直接使用document.getElementById。此外,确保在组件销毁时清理资源,比如在beforeUnmount钩子中移除iframe并释放URL,防止内存泄漏。 可能还需要处理错误情况,比如请求失败时的处理,或者PDF加载失败的情况。另外,服务器必须正确设置CORS头部,允许前端域的请求,否则即使前端正确处理,请求也会被浏览器拦截。 最后,测试时要注意不同浏览器的兼容性,尤其是处理Blob和打印相关的API是否存在差异。可能需要添加一些延迟来确保打印对话框在资源完全加载后弹出,比如使用setTimeout,但时间不宜过长或过短。</think>### Vue.js中实现跨域PDF打印的完整解决方案 #### 一、实现原理 通过AJAX请求获取PDF二进制流后,使用$window.URL.createObjectURL()$生成临时URL,通过隐藏iframe加载资源并触发$contentWindow.print()$方法。该方案有效规避了跨域限制(需配合CORS配置)[^1][^2]。 #### 二、具体实现步骤 1. **配置axios请求** ```javascript // Vue组件方法 async handlePrint() { try { const res = await axios.get('/api/print-pdf', { responseType: 'blob', // 关键配置项 headers: { Authorization: `Bearer ${token}` } }) this.generatePrintFrame(res.data) } catch (error) { console.error('打印请求失败:', error) } } ``` 2. **创建动态iframe** ```javascript methods: { generatePrintFrame(pdfData) { const blob = new Blob([pdfData], { type: 'application/pdf' }) const blobUrl = URL.createObjectURL(blob) // 创建隐藏iframe const iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = blobUrl // 加载完成后触发打印 iframe.onload = () => { const isEdge = navigator.userAgent.indexOf('Edg') > -1 setTimeout(() => { iframe.contentWindow?.print() // Edge浏览器需要延迟释放 isEdge ? setTimeout(() => this.cleanup(blobUrl), 3000) : this.cleanup(blobUrl) }, 500) } document.body.appendChild(iframe) }, cleanup(url) { URL.revokeObjectURL(url) const frames = document.querySelectorAll('iframe[style*="none"]') frames.forEach(frame => frame.remove()) } } ``` #### 三、关键注意事项 1. **CORS配置要求** - 服务器需设置响应头: ```http Access-Control-Allow-Origin: https://your-domain.com Access-Control-Expose-Headers: Content-Disposition ``` 2. **内存管理优化** - 使用$try...finally$确保资源释放: ```javascript finally { this.$nextTick(() => { URL.revokeObjectURL(this.printUrl) this.printUrl = null }) } ``` 3. **浏览器兼容处理** ```javascript // 处理Chrome打印弹窗阻塞 if (navigator.userAgent.indexOf('Chrome') > -1) { iframe.style.display = 'block' iframe.style.width = '0' iframe.style.height = '0' } ``` #### 四、扩展优化方案 1. **添加加载状态指示** ```javascript data() { return { isPrinting: false, printProgress: 0 } } // 在axios配置中添加进度监控 onDownloadProgress(progressEvent) { this.printProgress = Math.round( (progressEvent.loaded * 100) / progressEvent.total ) } ``` 2. **PDF预览增强** ```vue <template> <div v-if="previewUrl" class="preview-modal"> <embed :src="previewUrl" type="application/pdf" width="100%" height="600px"> </div> </template> ``` #### 五、错误处理机制 ```javascript // 统一错误处理 iframe.onerror = () => { this.cleanup(blobUrl) this.$emit('print-error', { code: 'LOAD_FAILED', message: 'PDF加载失败' }) } // 响应拦截器配置 axios.interceptors.response.use(response => { if (response.headers['content-type'] !== 'application/pdf') { throw new Error('Invalid content type') } return response }, error => { return Promise.reject({ code: 'NETWORK_ERROR', details: error.response?.status }) }) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值