【实战晋级】理解跨域以及工作中跨域问题的处理 - 1

简介: 相信大部分前端工程师在日常工作中经常使用 xhr 或者 fetch 从后端 api 里取数据然后进行二次处理,随后渲染到页面。

写在前面


相信大部分前端工程师在日常工作中经常使用 xhr 或者 fetch 从后端 api 里取数据然后进行二次处理,随后渲染到页面。

所以这个跨域问题也就屡见不鲜,当然在一些成熟的公司有自己的技术基础和储备这种问题都已经被处理掉一般不会遇到或者配置下就完事了,但并不是所有公司都有这个基础服务,所以这个时候就需要前端工程师自己来进行分析和处理。

所以本文就从这个角度来说下如何解决日常跨域问题,让我们更高效的和后端同学沟通,更快的解决问题完成工作目标。

现在网络上关于跨域的解析文章已经非常多了,再重复的说也很难说出花儿来。所以本文主要从发现问题和解决问题的思路出发,通过实际的代码来帮助大家更具象的理解和处理跨域。

当然跨域的解决方式多种多样,但本文主要说用的最多最灵活的(前端工作量最少)- CORS

跨域的理解


理解跨域不需要什么逻辑,跨域是浏览器的一种安全限制(同源策略),不允许脚本对其他域的资源进行直接访问,你能发请求但是浏览器会从中阻拦,要想解除这个限制就需要遵循一定的协议和规范办事(按规矩办事儿)就可以了。

什么情况下产生跨域


只要是 AJAX 要请求地址的端口、协议、域名(包括通过 ip 访问)只要其中一个不同就会产生跨域(你拿不到想要的数据)。

CORS介绍(真香)


CORS是一个 W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

完成 CORS 需要服务器和浏览器进行配合,除了 IE(IE10以下) 浏览器基本上都支持 。

对于前端来说实现 CORS 不需要做太多工作,都是浏览器自动完成的,浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS协议,就可以自由的进行数据交互了。

到这里理论的话就不说了,更详细的请看阮大佬的文章 http://www.ruanyifeng.com/blog/2016/04/cors.html

下面开始结合代码复现问题和解决问题。

问题以及处理


准备工作


  • 本机使用 node 和 koa2启动一个监听 8100端口的web服务


  • 指定一个接口 /getdata,并且返回 json 数据


  • 使用中间件 koa-static启动静态页面的访问


  • 模拟跨域,使用 localhost:8100访问 ip:8100/getdata接口则产生跨域


  • 静态页面内使用 xhr 对接发起请求


  • node端

/**
 * 服务入口
 */
var http = require('http');
var koaStatic = require('koa-static');
var path = require('path');
var koaBody = require('koa-body');
var Koa = require('koa2');
var app = new Koa();
var port = process.env.PORT || '8100';
//解析请求的数据为对象
app.use(koaBody());
//启动静态资源访问
app.use(koaStatic(
    path.resolve(__dirname, '../static')
));
//跨域处理
app.use((ctx) => {
    //指定一个接口和返回数据
    var path =ctx.path;
    if(path==='/getdata'){
        ctx.body=JSON.stringify({
            code:0,
            msg:'success',
            data:[]
        });
    }else{
        ctx.body='welcome';
    }
})
/**
 * 启动 web 服务
 */
var server = http.createServer(app.callback());
server.listen(port);
console.log('server start ......   ');

html

<body>
    <h2>跨域问题复现和解决</h2>
    <h3>使用 get 或者 post 发送数据 </h3>
    <h4>要发送的数据 a=1&b=2</h4>
    <button type="button" id="btn">发送数据</button>
</body>
<script>
function xhrSend() {
    var xhr = new XMLHttpRequest();   //创建对象
    xhr.open('POST', 'http://localhost:8100/getdata', true);
    xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
    xhr.send('a=1&b=2');//发送数据
    xhr.onreadystatechange = function () {
        console.log('state change', xhr.readyState);
        if (xhr.readyState == 4) {
            var obj = JSON.parse(xhr.responseText); //转为 json 格式
            console.log(obj);
        }
    }
}
document.getElementById('btn').addEventListener('click',function (e) {
        xhrSend();
});
</script>

接口验证

同源请求时正常拿到数据。

cf28e8707e20862eb84e6f3e30baec23_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

7af97944c669f5652f1c9fd003629e68_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

场景

用 post或者 get 请求接口数据,结果控制台报如下错误。

提示我们产生了跨域,需要设置响应头 Access-Control-Allow-Origin的值,把请求来源的 Origin加进去。

3d8119b6397ab9b9b38c3918a70ded8d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

报错解决

Origin是什么?

支持 COSR协议的浏览器会自动在请求头内携带这个头发给服务器,其值就是发起请求域的全写(协议+域名+端口)

f7e48a1e061e2dbd7409188d17b4084b_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

服务端设置'Origin'

ctx.set('Access-Control-Allow-Origin',ctx.headers.origin);

Access-Control-Allow-Origin是什么?

它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

//跨域处理
app.use((ctx) => {
    console.log('receive req');
    //指定一个接口和返回数据
    var path =ctx.path;
    if(path==='/getdata'){
        //服务端通过 ctx.headers.origin 获取请求中的origin
        + ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);
        ctx.body=JSON.stringify({
            code:0,
            msg:'success',
            data:[]
        });
    }else{
        ctx.body='welcome';
    }
})

问题解决

响应头里多了个这个 ,表示服务器允许这个地址进行数据请求

130e6bf0242a3ed2901f9e77fc4d31a3_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

可以正确的得到数据

fda11bd24144ee608ba75865ab9d230e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

搞清楚个事儿

先回到上面的代码产生跨域的时候,ajax 的请求已经发出去了,而且 status是200,服务端也收到了请求(我故意 log 了一个 receive data),但是浏览器的响应结果却是空的。


de08a519aabbce14d2206126f930b2e9_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

0e9204a674d62fb7cc4d5a9267422c9f_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

下图中看到,服务端已收到请求

5ba2426c7759436cdee0605410a16509_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

推断:出现这种情况应该是浏览器给禁止了,其实浏览器得到了数据,但是因为跨域并没有把数据交给xhr对象。

既然这样那就抓包再验证下

08de729b0b4dc0531ae834e2c48c9d84_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

从上图可以得到我们的猜测是正确的,还是浏览器做了手脚,所有的数据发送都正常进行了,只是最后关头浏览器插手了(安全机制)。

PS - 简单请求

虽然咱们上面只是处理 POST 的跨域,其实 GET、HEAD 是一样的,另外 Content-Typeapplication/x-www-form-urlencoded,当然也适用于 multipart/form-data、text/plain(文件上传和发送文本),有兴趣的可以自行修改下代码来进行在验证。

符合下列条件的都属于简单请求,上面的解决办法都适用。

2e96cb79bac58e96c556d66d726469cf_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

最后


本小节到这里就介绍完了,简单请求的跨域处理你了解了吗?

但是上面的 node 端代码存在一个问题,不知道大家有没有发现?

发现的请留言哦,在后面的小节我会说明,到时候咱们继续聊~

目录
相关文章
|
3月前
|
前端开发 应用服务中间件 API
"揭秘!面试官必问:你是如何巧妙绕过跨域难题的?前端代理VS服务器端CORS,哪个才是你的秘密武器?"
【8月更文挑战第21天】在软件开发中,尤其前后端分离架构下,跨域资源共享(CORS)是常见的挑战。主要解决方案有两种:一是服务器端配置CORS策略,通过设置响应头控制跨域访问权限,无需改动前端代码,增强安全性;二是前端代理转发,如使用Nginx或Webpack DevServer在开发环境中转发请求绕过同源策略,简化开发流程但不适用于生产环境。生产环境下应采用服务器端CORS策略以确保安全稳定。
51 0
|
6月前
|
JSON 前端开发 JavaScript
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
|
6月前
|
JSON 前端开发 安全
Web前端开发中的跨域问题及解决方案
【2月更文挑战第8天】在Web前端开发中,跨域是一个常见且具有挑战性的问题。本文将深入探讨跨域产生的原因、影响以及多种解决方案,帮助开发者更好地理解和解决跨域问题。
|
前端开发
前端学习笔记202306学习笔记第四十八天-代理解决跨域问题1
前端学习笔记202306学习笔记第四十八天-代理解决跨域问题1
37 0
|
网络协议 Java 数据库连接
java后端跨域 配置 代码
java后端跨域 配置 代码
121 0
|
JSON 前端开发 数据格式
【实战晋级】理解跨域以及工作中跨域问题的处理 - 2 预检请求
本文是第2节,紧接上1节 【实战晋级】理解跨域以及工作中跨域问题的处理 - 1。
211 0
【实战晋级】理解跨域以及工作中跨域问题的处理 - 2 预检请求
|
前端开发 文件存储 数据安全/隐私保护
【小刘带你玩儿前端】什么是跨域以及如何解决?
现在的web项目,很多都是前后端分离,特别容易出现跨域问题
【小刘带你玩儿前端】什么是跨域以及如何解决?
|
JavaScript Java
Java后端解决跨域问题
Java后端解决跨域问题
107 0
|
前端开发
前端工作总结221-跨域问题
前端工作总结221-跨域问题
69 0
前端工作总结221-跨域问题
|
前端开发 数据库 开发者
学习跨域的必要性| 学习笔记
快速学习学习跨域的必要性。