CRMEB的PHP版本跨域问题

1. /config/cookie.php修改为

return [
    'expire'    => 0,
    'path'      => '/',
    'domain'    => '',
    'secure'    => false,
    'httponly'  => false,
    'setcookie' => true,

    // 正确的 CORS 头(开发环境)
      'header'    => [
        'Access-Control-Allow-Origin'      => 'http://localhost:1617',
        'Access-Control-Allow-Credentials' => 'true',
        'Access-Control-Allow-Methods'     => 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
        // 临时兼容:把 authori-zation 也放进来(注意是连字符+全小写)
        'Access-Control-Allow-Headers'     => 'authorization, Authorization, authori-zation, content-type, x-requested-with, if-modified-since, if-none-match, if-unmodified-since, form-type, cb-lang',
        'Access-Control-Max-Age'           => '1728000',
        'Vary'                             => 'Origin',
    ],
    'token_name' => 'Authorization',
];

2. public/index.php修改为

//允许跨域
// === CORS(支持凭证)开始 ===
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
// 允许的前端域名白名单(按你实际前端域名填写)
$allowOrigins = [
 
    'https://0009.012539.cn',
    'http://localhost:1617',   // 本地调试可选
];

 
if ($origin && in_array($origin, $allowOrigins, true)) {
    header("Access-Control-Allow-Origin: $origin");
    header("Access-Control-Allow-Credentials: true");
    header("Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,OPTIONS");
    header("Access-Control-Allow-Headers: DNT,Keep-Alive,User-Agent,Cache-Control,Content-Type,Authorization,X-Requested-With,Platform,token");
    header("Vary: Origin"); // 让代理/缓存按来源区分
}

// 预检请求直接放行并返回 204(必须带上相同的 CORS 头)
if (strtoupper($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') {
    http_response_code(204);
    header("Content-Length: 0");
    exit();
}
// === CORS 结束 ===


//end

3. VUE后台/src/libs/request.js

// src/libs/request.js
// +---------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +---------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +---------------------------------------------------------------------

import axios from 'axios';
import { Message } from 'element-ui';
import { getCookies, removeCookies } from '@/libs/util';
import Setting from '@/setting';
import router from '@/router';

// 用实例自己的默认项;把 withCredentials 放到实例里(很关键)
const service = axios.create({
  baseURL: Setting.apiBaseURL,
  timeout: 10000,
  withCredentials: true, // ✅ 让跨域请求能带上 cookie
});

// ❌ 删掉这句(对实例没作用,而且容易误导):
// axios.defaults.withCredentials = true;

// 请求拦截器
service.interceptors.request.use(
  (config) => {
    // 统一 baseURL;kefu 用 kefuapi
    config.baseURL = config.kefu
      ? Setting.apiBaseURL.replace(/adminapi/, 'kefuapi')
      : Setting.apiBaseURL;

    // 上传文件时不要手动写 boundary,交给浏览器(可留可去)
    // if (config.file) {
    //   config.headers['Content-Type'] = 'multipart/form-data';
    // }

    const token = getCookies('token');
    const kefuToken = getCookies('kefu_token');

    // 🚫 彻底清掉历史错别字请求头,避免被浏览器带出去
    if (config.headers) {
      delete config.headers['authori-zation'];
      delete config.headers['Authori-zation'];
    } else {
      config.headers = {};
    }

    // ✅ 统一用标准 Authorization
    const accessToken = config.kefu ? kefuToken : token;
    if (accessToken) {
      // 如果后端不需要 Bearer,就改成:config.headers['Authorization'] = accessToken;
      config.headers['Authorization'] = `Bearer ${accessToken}`;
    }

    return config;
  },
  (error) => Promise.reject(error),
);

// 响应拦截器
service.interceptors.response.use(
  (response) => {
    // 兼容后端有时返回字符串的情况
    const raw = response && response.data;
    const obj = typeof raw === 'string' ? JSON.parse(raw) : (raw || {});
    const code = obj.status ?? 0;

    switch (code) {
      case 200:
        return obj;

      // 登录失效(后台)
      case 110002:
      case 110003:
      case 110004:
        localStorage.clear();
        removeCookies('token');
        removeCookies('expires_time');
        removeCookies('uuid');
        router.replace({ name: 'login' });
        return Promise.reject(obj);

      // 客服登录失效
      case 110005:
      case 110006:
      case 110007:
        removeCookies('kefuInfo');
        removeCookies('kefu_token');
        removeCookies('kefu_expires_time');
        removeCookies('kefu_uuid');
        router.replace({ path: '/kefu' });
        return Promise.reject(obj);

      case 110008:
        router.replace({ name: 'system_opendir_login' });
        return Promise.reject(obj);

      default:
        return Promise.reject(obj || { msg: '未知错误' });
    }
  },
  (error) => {
    // 这里以前传了 undefined 进去导致 element-ui 报 “type” 错误
    const msg =
      error?.response?.data?.msg ||
      error?.response?.data?.message ||
      error?.message ||
      '请求失败';
    Message.error(msg);
    return Promise.reject(error);
  },
);

export default service;


posted @ 2025-10-25 15:42  79524795  阅读(5)  评论(0)    收藏  举报