yinguangyao / blog

关于 JavaScript 前端开发、工作经验的一点点总结。

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

怎么解决跨域问题

yinguangyao opened this issue · comments

commented

最近在和后端联调的时候遇到了问题,由于后端那边没有创建数据表的权限(相关的新加坡同事也刚好休假),就导致没法把接口发布测试环境,不得不和他本机联调,这样就遇到了跨域的问题。

原来这边的前后端通信,前端都会请求网关(一个nodejs的中间层),网关对接口进行分发,这样是没有跨域问题的。但这次是前端直接请求后端本机的接口,就出现了跨域的问题。

代理

其实有挺多方法可以解决这个问题,比如使用 whistle 或者 charles 进行代理,这里以 whistle 为例,whistle拥有非常强大的功能,可以自定义规则:

/admin-api\.test\.airpay\.in\.th\/debug\/(.+)$/ http://10.12.160.249:8099/btcod/v1/$1

比如上面这句规则,就是将以 admin-api.test.airpay.in.th.debug 开头的请求转发到 http://10.12.160.249:8099/btcod/v1/ 上面。

但是呢,这边希望在本机联通后,给测试先在本地测试,所以为了不让测试再去配置一大堆麻烦的代理,我就想着在代码里面做一下修改。

OPTIONS

于是,我和后端商量,让他去设置一下 access-control-allow-origin,但这边的后端缺少解决跨域的经验,我也不清楚服务端怎么设置 CORS 才是正确的,导致我再次请求的时候,出现了 OPTIONS 请求,且响应码为301,可以说非常神奇了。

不管怎么样都无法绕过这个301,让我很头疼,后来刚哥让我想办法去绕过 OPTIONS 或者拦截 OPTIONS 请求。

对,这就涉及到跨域请求中的预检请求了。
跨域请求分为两种,一种是简单请求,一种是复杂请求。只有复杂请求会在正式发送请求之前,先发送一次 OPTIONS 请求,检查当前服务器是否允许该跨域请求,如果是则再发送正式请求。
满足以下情况的都是复杂请求:

image.png-112.8kB

为什么我的请求是复杂请求呢?很明显满足了最后一条。
一般来说,axios 将 JavaScript 对象序列化为 JSON 来发送,也就是说会使用 application/json作为Content-Type

于是我就手动设置了请求的 Content-Type,将其设置为 application/x-www-form-urlencoded
一般来说,表单提交的时候不会跨域,这是为什么呢?因为表单提交到另一个域名后,原来的页面就无法拿到新页面的数据了。
但是我们现在传给接口的数据格式还是 JSON,该怎么办呢?
这里有两种方式:

  1. 使用 URLSearchParams 转换为 FormData 格式
  2. 使用 qs 库来处理

当然了,还需要后端对传入的 Form 数据进行处理,毕竟原来的是 JSON。

修改响应头

除了上面说的这些,还有一个最简单的方式,那就是通过 whistle 代理来修改接口的响应头,给它设置 Access-Control-Allow-Origin 就可以了,例如在 whistle 里面可以这样设置。

https://giro.test.airpay.in.th/ibanking/v1/gateway/mbanking_init/ resHeaders://{corsHeader.json}

// corsHeader.json
{
"Access-Control-Allow-Headers": "Content-Type, Access-Control-Allow-Headers, Authorization, token",
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true",
"content-type": "application/json",
"status": 200
}

总结

经过这么一通处理,终于解决了问题,对跨域的理解也更深一步了。当然,原本很简单的问题为什么会搞得这么复杂呢?主要还是自己缺乏服务端开发的知识,后端也比较忙,不太愿意帮我去解决这个问题,只能自己硬着头皮去探索了。