[CodeIgniter4]前后端分离跨域问题

一、背景

最近在弄毕业设计啦,采用CodeIgniter4+Vue3来做的,前后端分离项目,首先便是跨域问题。一顿搜索无果后,自己折腾了一个解决方案,希望能帮助到看到这篇文章的你。

二、跨域问题

由于浏览器的 同源策略 限制,使用前后端分离的模式下,前端和后端的域名一般都不是一样的,在我的项目中,前端是使用二级域名,而后端是使用三级域名,此时前后端就不同源了,就产生了跨域问题。

同源即两个页面具有相同的协议(protocol),主机(host)和端口号(port)

下表即我目前遇到的情况

域名

域名级别

框架

前端

example.com

二级域名

Vue3

后端

api.example.com

三级域名

CodeIgniter4

三、解决方法

1.问题

在前端往后端发送请求时,控制台会输出跨域报错,无法拿到数据。此时控制台会显示Access-Control-Allow-Origin不包含当前发送请求页面的相关提示。

2.解决思路

最常见的方法便是把响应头设置为

Access-Control-Allow-Origin: *

但这样每个接口都要设置一遍,会比较麻烦。

此时我们需要用到CodeIgniter4中的控制器过滤器里面的 前置过滤器

前置过滤器的官方文档

然后在前置过滤器中完成响应头的设定即可。

3.实现

(1)在app下找到Filters文件夹,如果没有,请先创建;

(2)在Filters文件夹下创建CorsFilter.php文件。

(3)写入以下代码

代码语言:php
复制
<?php

namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class CorsFilter implements FilterInterface
{
// 前置过滤器
public function before(RequestInterface request, arguments = null)
{
$response = service('response');
$response->setHeader('Access-Control-Allow-Origin', '*');
}

//--------------------------------------------------------------------
// 后置过滤器
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
    // Do something here

}

}

(4)在app/Config/Filters.php中配置我们刚刚创建的过滤器。大功告成!

代码语言:php
复制
// ----上面代码省略,无需修改----

public $aliases = [
'csrf' => CSRF::class,
'toolbar' => DebugToolbar::class,
'honeypot' => Honeypot::class,
'cors' => CorsFilter::class
];

public $globals = [
'before' => [
// 配置生效页面,except里面配置的时不生效页面
'cors'=> ['except' => ['/yourPage1', '/yourPage2/detail']]
],
'after' => [
],
];

// ----下面代码省略,无需修改----

4.自定义请求头(无此需求可跳过)

由于我的项目需要自定义请求头,这时候又得另外处理一下。

使用 自定义请求头 时,前端(客户端浏览器)会先发出一个OPTIONS请求,来判断是否可用,如果这时候没有进行设置的话,同样也是无法完成跨域的。

在上面的基础上加入以下代码

代码语言:php
复制
// 允许各种方法
$response->setHeader('Access-Control-Allow-Method', '*');
// 允许User-Token请求头(如果你是其他的自定义头,请更改)
$response->setHeader('Access-Control-Allow-Headers', 'User-Token');
// 判断请求的方法是否为OPTIONS,如果为OPTIONS,则返回200OK,表示服务器可以接受该方法
if($request->getMethod(FALSE)=='options'){
return $response->setStatusCode(200,'OK');
}

加入处理自定义请求头的完整控制器过滤器代码

代码语言:php
复制
<?php

namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class CorsFilter implements FilterInterface
{
// 前置过滤器
public function before(RequestInterface request, arguments = null)
{
$response = service('response');
$response->setHeader('Access-Control-Allow-Origin', '');
$response->setHeader('Access-Control-Allow-Method', '
');
$response->setHeader('Access-Control-Allow-Headers', 'User-Token');

    if($request-&gt;getMethod(FALSE)==&#39;options&#39;){
        return $response-&gt;setStatusCode(200,&#39;OK&#39;);
    }
}

//--------------------------------------------------------------------
// 后置过滤器
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
    // Do something here

}

}

四、注意事项

在创建过滤器文件中,不能删除后置过滤器

错误代码

代码语言:php
复制
<?php
// 错误代码示例!!!!
namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class CorsFilter implements FilterInterface
{
// 前置过滤器
public function before(RequestInterface request, arguments = null)
{
$response = service('response');
$response->setHeader('Access-Control-Allow-Origin', '*');
}
}
// 错误代码示例!!!!

正确代码

代码语言:php
复制
<?php

namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class CorsFilter implements FilterInterface
{
// 前置过滤器
public function before(RequestInterface request, arguments = null)
{
$response = service('response');
$response->setHeader('Access-Control-Allow-Origin', '*');
}

//--------------------------------------------------------------------
// 后置过滤器
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
    // Do something here

}

}