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

2022-03-03 12:45:59 浏览数 (2)

一、背景

最近在弄毕业设计啦,采用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 AppFilters;
use CodeIgniterHTTPRequestInterface;
use CodeIgniterHTTPResponseInterface;
use CodeIgniterFiltersFilterInterface;

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 AppFilters;
use CodeIgniterHTTPRequestInterface;
use CodeIgniterHTTPResponseInterface;
use CodeIgniterFiltersFilterInterface;

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->getMethod(FALSE)=='options'){
            return $response->setStatusCode(200,'OK');
        }
    }

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

    }
}

四、注意事项

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

错误代码

代码语言:php复制
<?php
// 错误代码示例!!!!
namespace AppFilters;
use CodeIgniterHTTPRequestInterface;
use CodeIgniterHTTPResponseInterface;
use CodeIgniterFiltersFilterInterface;

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

正确代码

代码语言:php复制
<?php

namespace AppFilters;
use CodeIgniterHTTPRequestInterface;
use CodeIgniterHTTPResponseInterface;
use CodeIgniterFiltersFilterInterface;

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

    }
}

0 人点赞