解决:前端请求跨域问题
- 问题一:Access to XMLHttpRequest at 'https://xxx/ICN40310000075_1687926884828.pdf' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
- 问题二:Access to XMLHttpRequest at 'http://127.0.0.1:8080/test8' from origin 'http://localhost:63342' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
- 一·问题描述:
- 1.一个下载文件的url接口,直接浏览器访问是可以正常下载文件,但是在页面里通过js发起XHR请求去访问下载文件接口,总是会报跨域问题,从而被浏览器拦截了请求
- 2.控制台报错截图:如下所示
- 二·问题原因:
- 1.违反了浏览器的“同源协议”
- 2.后台没有做相关的跨域处理
- 3.浏览器直接访问第三方接口资源,是可以跳过“同源协议”的
- 三·解决方案:
- 方案一:遵循同源策略,不发起跨域请求,尽量在同一个服务里面试着解决业务需求。
- 方案二:不遵循同源协议,发起不携带credentials凭证的跨域请求,那就只能在被访问的接口服务后台做允许跨域的处理才行;其实本质就是给接口加上一个响应头:Access-Control-Allow-Origin:*,适用于多系统或者多服务之间的接口对接场景
- 方案三:不遵循同源协议,发起携带credentials凭证的跨域请求,那就只能在被访问的接口服务后台做允许跨域的处理才行;适用于多系统或者多服务之间的接口对接场景
- 四·相关参考文章:
- 1.什么是跨域,后端工程师如何处理跨域?
问题一:Access to XMLHttpRequest at ‘https://xxx/ICN40310000075_1687926884828.pdf’ from origin ‘http://localhost:63342’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
问题二:Access to XMLHttpRequest at ‘http://127.0.0.1:8080/test8’ from origin ‘http://localhost:63342’ has been blocked by CORS policy: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
一·问题描述:
1.一个下载文件的url接口,直接浏览器访问是可以正常下载文件,但是在页面里通过js发起XHR请求去访问下载文件接口,总是会报跨域问题,从而被浏览器拦截了请求
2.控制台报错截图:如下所示
Access to XMLHttpRequest at ‘https://xxx/ICN40310000075_1687926884828.pdf’ from origin ‘http://localhost:63342’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Access to XMLHttpRequest at ‘http://127.0.0.1:8080/test8’ from origin ‘http://localhost:63342’ has been blocked by CORS policy: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
二·问题原因:
1.违反了浏览器的“同源协议”
什么是同源协议?
同源策略/SOP (Same origin policy)是一种约定,由 Netscape 公司1995年引入浏览器。
同源策略是指在 Web 浏览器中:
若某个网站的脚本(比如:js脚本)需要去访问另一个网站的相关资源;那这两个网站就必须同时满足下面三个条件才行,否则浏览器就会自动拦截脚本发起的相关请求:
1、协议相同;
2、域名相同;
3、端口相同;
2.后台没有做相关的跨域处理
3.浏览器直接访问第三方接口资源,是可以跳过“同源协议”的
三·解决方案:
方案一:遵循同源策略,不发起跨域请求,尽量在同一个服务里面试着解决业务需求。
方案二:不遵循同源协议,发起不携带credentials凭证的跨域请求,那就只能在被访问的接口服务后台做允许跨域的处理才行;其实本质就是给接口加上一个响应头:Access-Control-Allow-Origin:*,适用于多系统或者多服务之间的接口对接场景
前端发起不携带credentials凭证请求示例:
/**
* 后台响应二进制流,前端接收处理并当作文件下载
*
* @param url 下载文件的接口url
* @param data 接口必要的参数,json格式
* @return
* @author LiuMingFu
* @date 2023-07-01
*/
function downloadFile(url, data) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true); // 请求方式,看具体接口情况决定
xhr.withCredentials = false; //不携带凭证,默认就是false
xhr.responseType = "blob"; // 返回类型blob
// 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
xhr.onload = function () {
// 请求完成
var blob = this.response;
var downloadLink = document.createElement('a');
let path = URL.createObjectURL(blob);
console.log("path=" + path);
downloadLink.href = path;
downloadLink.download = 'hello.pdf'; // 替换为你想要的文件名和扩展名
downloadLink.click();
alert("下载完成");
};
xhr.onerror = function () {
alert("下载失败")
};
// 发送ajax请求
xhr.send(JSON.stringify(data)); // 数据格式,看具体接口情况决定
}
后端接口处理示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", "*"); // 或者替换为具体的域名
// 其他响应设置和处理
}
在Servlet的实现类中的doGet()或doPost()等方法中,添加上述代码即可设置Access-Control-Allow-Origin头。response对象提供了setHeader()方法,用于设置响应头的值。在实际应用中,为了安全考虑,应该将 * 通配符替换为具体的域名,以限制可访问资源的域。
注意:该方案是一般情况下,前端没有包含credentials凭证的跨域解决方案
方案三:不遵循同源协议,发起携带credentials凭证的跨域请求,那就只能在被访问的接口服务后台做允许跨域的处理才行;适用于多系统或者多服务之间的接口对接场景
前端发起携带凭证的跨域请求示例:
/**
* 后台响应二进制流,前端接收处理并当作文件下载
*
* @param url 下载文件的接口url
* @param data 接口必要的参数,json格式
* @return
* @author LiuMingFu
* @date 2023-07-01
*/
function downloadFile(url, data) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true); // 请求方式,看具体接口情况决定
xhr.withCredentials = true; //携带凭证,默认是false
xhr.responseType = "blob"; // 返回类型blob
// 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
xhr.onload = function () {
// 请求完成
var blob = this.response;
var downloadLink = document.createElement('a');
let path = URL.createObjectURL(blob);
console.log("path=" + path);
downloadLink.href = path;
downloadLink.download = 'hello.pdf'; // 替换为你想要的文件名和扩展名
downloadLink.click();
alert("下载完成");
};
xhr.onerror = function () {
alert("下载失败")
};
// 发送ajax请求
xhr.send(JSON.stringify(data)); // 数据格式,看具体接口情况决定
}
后端服务接口代码处理示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", origin);//具体的域名,不能使用*
response.setHeader("Access-Control-Allow-Credentials", "true");
// 其他响应设置和处理
}
在上述代码中,我们首先通过request.getHeader(“Origin”)获取到请求的来源域名,然后将其设置为Access-Control-Allow-Origin头的值,这里不能使用*号。同时设置Access-Control-Allow-Credentials为"true",允许携带凭证信息(即使跨域请求)。
这样设置以后,当使用withCredentials属性设置为true时,你的请求就可以成功通过CORS策略,包括携带相应的身份验证信息和cookie。
请记住,在生产环境中,应根据实际需求仔细控制和限制Access-Control-Allow-Origin头的值,仅允许来自特定域的跨域访问。
注意:要是在遵循同源协议的情况下,无论带不带credentials凭证,都是可以成功发起请求访问后台资源的