前台访问服务的方法

安全性角度

核心分为「直接访问公开服务」和「通过后端中转访问私密服务」两类

场景类型 适用场景 安全等级 关键说明
直接访问公开服务 无需敏感凭证、公开可访问的API(如天气API、公开资讯API) 直接通过前端请求,无需后端介入
通过后端中转访问私密服务 需要敏感凭证(如翻译API的appid/secretKey)、需权限校验的服务 前端仅传递业务参数,敏感逻辑由后端处理

前端访问服务的核心是基于HTTP/HTTPS协议(或WebSocket/SSE等特殊协议)实现数据交互,下面按「原生无依赖」「第三方库」「跨端/特殊场景」「实时通信」四大类展开,每类包含详细用法、示例、优缺点及适用场景,覆盖绝大多数前端开发需求。

一、第一类:原生无依赖请求方式(无需安装第三方包)

这类方式依赖浏览器/运行环境内置API,无需额外引入依赖,兼容性各有差异。

1. XMLHttpRequest(传统原生方式,兼容所有浏览器)

这是最早的前端网络请求API,兼容包括IE在内的所有浏览器,现在虽被fetch/axios替代,但在老旧项目或特殊兼容场景仍有使用。

适用场景
  • 兼容IE6+等老旧浏览器;
  • 需精细控制请求流程(如上传进度监控)。
完整代码示例(百度翻译中转请求)
javascript 复制代码
/**
 * 原生XMLHttpRequest访问后端中转接口
 * @param {string} query 待翻译文本
 * @param {string} from 源语言
 * @param {string} to 目标语言
 * @returns {Promise<Object>} 翻译结果
 */
export function baiduTranslateByXHR(query, from = 'auto', to = 'en') {
  return new Promise((resolve, reject) => {
    // 前置参数校验
    if (!query?.trim()) {
      reject(new Error('请传入有效的待翻译文本'));
      return;
    }

    // 1. 创建XHR实例
    const xhr = new XMLHttpRequest();

    // 2. 配置请求(方法、地址、是否异步)
    const url = 'http://localhost:3000/api/translate/baidu';
    xhr.open('POST', url, true); // true表示异步请求

    // 3. 设置请求头(传递JSON需配置Content-Type)
    xhr.setRequestHeader('Content-Type', 'application/json');

    // 4. 配置超时时间(单位:毫秒)
    xhr.timeout = 8000;

    // 5. 监控请求状态变化
    xhr.onreadystatechange = function () {
      // readyState=4 表示请求完成(响应已接收)
      if (xhr.readyState === 4) {
        // status=200 表示请求成功
        if (xhr.status >= 200 && xhr.status < 300) {
          try {
            // 解析JSON响应体
            const data = JSON.parse(xhr.responseText);
            if (data.code !== 0) {
              reject(new Error(data.msg || '翻译失败'));
              return;
            }
            resolve(data.data);
          } catch (error) {
            reject(new Error('响应数据解析失败:' + error.message));
          }
        } else {
          // 非2xx状态码视为失败
          reject(new Error(`请求失败,状态码:${xhr.status},信息:${xhr.statusText}`));
        }
      }
    };

    // 6. 监控超时事件
    xhr.ontimeout = function () {
      reject(new Error('请求超时,请稍后重试'));
    };

    // 7. 监控网络错误(如断网)
    xhr.onerror = function () {
      reject(new Error('网络异常,请检查网络连接'));
    };

    // 8. 监控上传进度(可选,适用于文件上传场景)
    xhr.upload.onprogress = function (e) {
      if (e.lengthComputable) {
        const progress = (e.loaded / e.total) * 100;
        console.log(`上传进度:${progress.toFixed(2)}%`);
      }
    };

    // 9. 发送请求(JSON格式需手动序列化)
    const requestData = JSON.stringify({ query, from, to });
    xhr.send(requestData);
  });
}

// 业务调用
async function useXHRTranslate() {
  try {
    const result = await baiduTranslateByXHR('你好世界', 'auto', 'en');
    console.log('XHR翻译结果:', result.text);
  } catch (error) {
    console.error('XHR翻译失败:', error.message);
    window.$message?.error(error.message);
  }
}
优缺点
  • 优点:兼容性极强(支持老旧浏览器)、可精细控制请求流程(进度监控、超时控制);
  • 缺点:API繁琐、需手动处理JSON序列化/解析、不支持Promise链式调用(需手动封装Promise)。
2. fetch(现代原生API,替代XHR)

ES6+引入的现代原生请求API,基于Promise设计,语法更简洁,无需手动封装Promise,是原生请求的首选。

适用场景
  • 现代浏览器/前端项目(不兼容IE);
  • 无需复杂请求配置,追求轻量无依赖。
详细示例(含超时、取消请求)
javascript 复制代码
/**
 * fetch访问服务(含超时、取消请求)
 * @param {string} query 待翻译文本
 * @param {string} from 源语言
 * @param {string} to 目标语言
 * @returns {Promise<Object>} 翻译结果
 */
export async function baiduTranslateByFetch(query, from = 'auto', to = 'en') {
  if (!query?.trim()) {
    throw new Error('请传入有效的待翻译文本');
  }

  // 1. 创建AbortController(用于取消请求/设置超时)
  const controller = new AbortController();
  const signal = controller.signal;

  // 2. 设置超时取消请求
  const timeoutId = setTimeout(() => {
    controller.abort(); // 超时后取消请求
    throw new Error('请求超时,请稍后重试');
  }, 8000);

  try {
    const response = await fetch('http://localhost:3000/api/translate/baidu', {
      method: 'POST', // 请求方法
      headers: {
        'Content-Type': 'application/json', // JSON请求头
      },
      body: JSON.stringify({ query, from, to }), // 请求体序列化
      signal: signal, // 关联取消信号
      credentials: 'include' // 携带Cookie(跨域时需后端配合)
    });

    // 清除超时定时器
    clearTimeout(timeoutId);

    // 3. 判断响应是否成功(fetch仅在网络错误时抛出异常,非2xx状态码需手动判断)
    if (!response.ok) {
      throw new Error(`请求失败,状态码:${response.status},信息:${response.statusText}`);
    }

    // 4. 解析响应体(根据响应格式选择对应方法)
    const data = await response.json(); // JSON格式
    // const data = await response.text(); // 纯文本格式
    // const data = await response.blob(); // 二进制文件格式

    // 5. 处理业务错误
    if (data.code !== 0) {
      throw new Error(data.msg || '翻译失败');
    }

    return data.data;
  } catch (error) {
    // 捕获取消请求异常
    if (error.name === 'AbortError') {
      throw new Error('请求已被取消(超时/手动取消)');
    }
    throw new Error('fetch请求失败:' + error.message);
  }
}

// 业务调用
async function useFetchTranslate() {
  try {
    const result = await baiduTranslateByFetch('测试文本', 'auto', 'en');
    console.log('fetch翻译结果:', result.text);
  } catch (error) {
    console.error('fetch翻译失败:', error.message);
    window.$message?.error(error.message);
  }
}
优缺点
  • 优点:语法简洁、基于Promise、无需第三方依赖、支持流式响应;
  • 缺点:不兼容IE、非2xx状态码不自动抛出异常、超时/取消请求需手动通过AbortController实现、默认不携带Cookie。
3. SSE(Server-Sent Events,服务器单向推送)

基于HTTP协议的单向实时通信方式,由服务器主动向客户端推送数据(如消息通知、实时日志),前端无需轮询。

适用场景
  • 服务器单向推送数据(如实时公告、数据监控、日志推送);
  • 无需客户端向服务器发送实时数据的场景。
完整代码示例
javascript 复制代码
/**
 * 前端通过SSE接收服务器实时推送
 * @param {string} url 服务器SSE接口地址
 * @returns {EventSource} SSE实例
 */
export function createSSEConnection(url) {
  // 1. 创建EventSource实例(自动保持长连接)
  const eventSource = new EventSource(url, {
    withCredentials: true // 携带Cookie(跨域时需后端配合)
  });

  // 2. 监听普通消息(服务器默认发送的message事件)
  eventSource.onmessage = function (e) {
    try {
      const data = JSON.parse(e.data);
      console.log('SSE接收普通消息:', data);
      // 业务处理(如显示实时通知)
      window.$message?.info(`实时通知:${data.content}`);
    } catch (error) {
      console.error('SSE消息解析失败:', error.message);
    }
  };

  // 3. 监听自定义事件(服务器指定的事件类型)
  eventSource.addEventListener('translateProgress', function (e) {
    const progressData = JSON.parse(e.data);
    console.log('翻译进度更新:', progressData.progress + '%');
  });

  // 4. 监听连接成功事件
  eventSource.onopen = function () {
    console.log('SSE连接成功,已建立长连接');
  };

  // 5. 监听错误事件
  eventSource.onerror = function (e) {
    if (eventSource.readyState === EventSource.CLOSED) {
      console.error('SSE连接已关闭');
    } else if (eventSource.readyState === EventSource.CONNECTING) {
      console.warn('SSE连接断开,正在重连...');
    } else {
      console.error('SSE连接异常:', e);
    }
  };

  // 6. 暴露关闭连接的方法
  eventSource.closeConnection = function () {
    eventSource.close();
    console.log('SSE连接已手动关闭');
  };

  return eventSource;
}

// 业务调用
const sseInstance = createSSEConnection('http://localhost:3000/api/sse/translate');
// 手动关闭连接(如组件销毁时)
// sseInstance.closeConnection();
优缺点
  • 优点:基于HTTP、无需额外协议、自动重连、轻量高效、支持自定义事件;
  • 缺点:单向通信(客户端无法向服务器实时推送)、不支持二进制数据、部分浏览器兼容性有限。
4. WebSocket(双向实时通信)

基于TCP协议的全双工通信方式,客户端和服务器可双向实时传递数据,适用于实时交互场景。

适用场景
  • 双向实时通信(如聊天系统、实时协作编辑、游戏互动);
  • 高频数据交互(无需多次建立HTTP连接)。
完整代码示例
javascript 复制代码
/**
 * 前端通过WebSocket建立双向连接
 * @param {string} url WebSocket服务器地址(ws://或wss://)
 * @returns {WebSocket} WebSocket实例
 */
export function createWebSocketConnection(url) {
  // 1. 创建WebSocket实例(ws://明文,wss://加密,对应HTTP/HTTPS)
  const ws = new WebSocket(url);

  // 2. 监听连接成功事件
  ws.onopen = function () {
    console.log('WebSocket连接成功');
    // 连接成功后发送初始化消息
    ws.send(JSON.stringify({
      type: 'init',
      data: '前端已连接'
    }));
  };

  // 3. 监听服务器推送的消息
  ws.onmessage = function (e) {
    try {
      const data = JSON.parse(e.data);
      console.log('WebSocket接收消息:', data);
      // 区分消息类型处理
      switch (data.type) {
        case 'translateResult':
          console.log('实时翻译结果:', data.content);
          window.$message?.success('翻译完成:' + data.content);
          break;
        case 'error':
          console.error('WebSocket错误消息:', data.msg);
          window.$message?.error(data.msg);
          break;
        default:
          console.log('未知消息类型:', data);
      }
    } catch (error) {
      console.error('WebSocket消息解析失败:', error.message);
    }
  };

  // 4. 监听连接关闭事件
  ws.onclose = function (e) {
    console.log(`WebSocket连接关闭,代码:${e.code},原因:${e.reason}`);
    // 可选:自动重连
    if (e.code !== 1000) { // 1000表示正常关闭
      setTimeout(() => {
        console.log('WebSocket正在重连...');
        createWebSocketConnection(url);
      }, 3000);
    }
  };

  // 5. 监听错误事件
  ws.onerror = function (e) {
    console.error('WebSocket连接异常:', e);
  };

  // 6. 暴露发送消息的方法(封装JSON序列化)
  ws.sendMsg = function (type, data) {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ type, data }));
    } else {
      console.error('WebSocket未连接,无法发送消息');
    }
  };

  return ws;
}

// 业务调用
const wsInstance = createWebSocketConnection('ws://localhost:3000/ws/translate');
// 发送翻译请求
wsInstance.sendMsg('translate', { query: '你好世界', from: 'auto', to: 'en' });
// 手动关闭连接
// wsInstance.close(1000, '客户端主动关闭');
优缺点
  • 优点:全双工通信、实时性高、无HTTP请求头开销、支持二进制数据;
  • 缺点:协议复杂(非HTTP)、需服务器支持WebSocket、重连逻辑需手动实现、跨域配置复杂。
5. JSONP(跨域兼容方案,现已基本淘汰)

基于<script>标签跨域特性实现的请求方式,仅支持GET请求,是老旧浏览器跨域的解决方案,现已被CORS替代。

适用场景
  • 兼容不支持CORS的老旧浏览器(如IE8/9);
  • 简单GET请求的跨域场景(现已极少使用)。
完整代码示例
javascript 复制代码
/**
 * JSONP请求(仅支持GET)
 * @param {string} url 请求地址
 * @param {Object} params 请求参数
 * @param {string} callbackName 回调函数名
 * @returns {Promise<Object>} 请求结果
 */
export function jsonpRequest(url, params, callbackName = 'jsonpCallback') {
  return new Promise((resolve, reject) => {
    // 1. 生成唯一回调函数名(避免冲突)
    const uniqueCallbackName = `${callbackName}_${Date.now()}_${Math.floor(Math.random() * 10000)}`;

    // 2. 拼接请求参数(含回调函数名)
    const paramStr = Object.keys(params).map(key => {
      return `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`;
    }).join('&') + `&callback=${uniqueCallbackName}`;

    // 3. 创建script标签
    const script = document.createElement('script');
    script.src = `${url}?${paramStr}`;
    script.type = 'text/javascript';
    script.async = true;

    // 4. 定义全局回调函数
    window[uniqueCallbackName] = function (data) {
      try {
        resolve(data);
      } finally {
        // 清理全局函数和script标签
        delete window[uniqueCallbackName];
        document.body.removeChild(script);
      }
    };

    // 5. 监听script加载错误
    script.onerror = function () {
      reject(new Error('JSONP请求失败'));
      // 清理资源
      delete window[uniqueCallbackName];
      document.body.removeChild(script);
    };

    // 6. 插入script标签发起请求
    document.body.appendChild(script);
  });
}

// 业务调用
async function useJSONP() {
  try {
    const result = await jsonpRequest('https://xxx.com/api/public/translate', {
      q: '你好世界',
      from: 'auto',
      to: 'en'
    });
    console.log('JSONP请求结果:', result);
  } catch (error) {
    console.error('JSONP请求失败:', error.message);
  }
}
优缺点
  • 优点:兼容老旧浏览器、无需后端配置CORS、实现简单;
  • 缺点:仅支持GET请求、存在安全风险(易受XSS攻击)、无法监控请求进度/超时、现已基本被CORS替代。

二、第二类:第三方库请求方式(主流常用)

这类方式基于原生API封装,提供更简洁的语法、更强大的功能(如拦截器、取消请求、自动序列化),是现代前端开发的首选。

1. axios(最主流,功能完善)

基于Promise的HTTP请求库,支持浏览器和Node.js环境,封装了拦截器、超时控制、自动JSON解析等功能,生态完善。

适用场景
  • 绝大多数前端项目(Vue/React/Angular等);
  • 需复杂请求配置(拦截器、取消请求、批量请求)的场景。
详细示例(含拦截器、取消请求、批量请求)
javascript 复制代码
import axios from 'axios';

// 1. 创建axios实例(统一配置基础参数)
const request = axios.create({
  baseURL: 'http://localhost:3000/api', // 基础请求地址
  timeout: 8000, // 全局超时时间
  headers: {
    'Content-Type': 'application/json' // 全局请求头
  },
  withCredentials: true // 全局携带Cookie
});

// 2. 请求拦截器(发送请求前处理,如添加token)
request.interceptors.request.use(
  (config) => {
    // 给所有请求添加token(登录后存储在localStorage)
    const token = localStorage.getItem('token');
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`;
    }
    console.log('请求配置:', config);
    return config;
  },
  (error) => {
    // 请求错误预处理
    console.error('请求拦截器错误:', error);
    return Promise.reject(error);
  }
);

// 3. 响应拦截器(接收响应后处理,如统一错误处理)
request.interceptors.response.use(
  (response) => {
    // 统一处理响应数据,只返回业务数据
    return response.data;
  },
  (error) => {
    // 统一处理响应错误
    let errorMsg = '请求失败';
    if (axios.isAxiosError(error)) {
      if (error.response) {
        // 有响应状态码的错误
        const status = error.response.status;
        const data = error.response.data;
        switch (status) {
          case 401:
            errorMsg = '未登录或登录过期,请重新登录';
            localStorage.removeItem('token');
            // 跳转到登录页
            window.location.href = '/login';
            break;
          case 403:
            errorMsg = '无权限访问该资源';
            break;
          case 404:
            errorMsg = '请求地址不存在';
            break;
          case 500:
            errorMsg = '服务器内部错误,请稍后重试';
            break;
          default:
            errorMsg = data.msg || `请求失败,状态码:${status}`;
        }
      } else if (error.request) {
        // 无响应的错误(网络错误、超时)
        errorMsg = '网络异常或请求超时,请检查网络连接';
      }
    }
    console.error('响应拦截器错误:', errorMsg);
    window.$message?.error(errorMsg);
    return Promise.reject(new Error(errorMsg));
  }
);

// 4. 翻译请求(基于封装的axios实例)
export async function baiduTranslateByAxios(query, from = 'auto', to = 'en') {
  if (!query?.trim()) {
    throw new Error('请传入有效的待翻译文本');
  }

  // 取消请求示例(创建取消令牌)
  const CancelToken = axios.CancelToken;
  const source = CancelToken.source();

  // 可选:手动取消请求(如组件销毁时)
  // source.cancel('请求已被手动取消');

  try {
    const data = await request.post('/translate/baidu', {
      query,
      from,
      to
    }, {
      cancelToken: source.token // 关联取消令牌
    });

    // 处理业务错误
    if (data.code !== 0) {
      throw new Error(data.msg || '翻译失败');
    }

    return data.data;
  } catch (error) {
    // 捕获取消请求异常
    if (axios.isCancel(error)) {
      console.log('请求已取消:', error.message);
    } else {
      throw error;
    }
  }
}

// 5. 批量请求示例(同时发起多个请求)
export async function batchTranslate(requestList) {
  try {
    // 同时发起多个翻译请求,等待所有请求完成
    const results = await Promise.all(
      requestList.map(item => 
        request.post('/translate/baidu', {
          query: item.query,
          from: item.from || 'auto',
          to: item.to || 'en'
        })
      )
    );
    return results.map(res => res.data);
  } catch (error) {
    console.error('批量翻译失败:', error.message);
    throw error;
  }
}

// 业务调用
async function useAxiosTranslate() {
  try {
    const result = await baiduTranslateByAxios('测试文本', 'auto', 'en');
    console.log('axios翻译结果:', result.text);

    // 批量翻译
    const batchResult = await batchTranslate([
      { query: '你好' },
      { query: '世界', to: 'ja' }
    ]);
    console.log('批量翻译结果:', batchResult);
  } catch (error) {
    console.error('axios翻译失败:', error.message);
  }
}
优缺点
  • 优点:语法简洁、支持拦截器、自动JSON解析、超时控制、取消请求、批量请求、兼容浏览器/Node.js;
  • 缺点:需额外安装依赖(体积较小,影响可忽略)。
2. superagent(轻量灵活的请求库)

轻量的HTTP请求库,语法简洁,支持链式调用,功能丰富,适用于中小型项目。

适用场景
  • 中小型前端项目;
  • 追求轻量、灵活配置的场景。
完整代码示例
javascript 复制代码
import superagent from 'superagent';

/**
 * superagent请求翻译接口
 * @param {string} query 待翻译文本
 * @param {string} from 源语言
 * @param {string} to 目标语言
 * @returns {Promise<Object>} 翻译结果
 */
export async function baiduTranslateBySuperagent(query, from = 'auto', to = 'en') {
  if (!query?.trim()) {
    throw new Error('请传入有效的待翻译文本');
  }

  try {
    const response = await superagent
      .post('http://localhost:3000/api/translate/baidu') // 请求方法+地址
      .set('Content-Type', 'application/json') // 设置请求头
      .send({ query, from, to }) // 发送请求体
      .timeout(8000) // 超时设置
      .withCredentials(); // 携带Cookie

    const data = response.body;
    if (data.code !== 0) {
      throw new Error(data.msg || '翻译失败');
    }

    return data.data;
  } catch (error) {
    let errorMsg = 'superagent请求失败';
    if (error.timeout) {
      errorMsg = '请求超时';
    } else if (error.response) {
      errorMsg = `请求失败,状态码:${error.response.status},信息:${error.response.text}`;
    } else {
      errorMsg = error.message;
    }
    console.error(errorMsg);
    window.$message?.error(errorMsg);
    throw new Error(errorMsg);
  }
}

// 业务调用
async function useSuperagentTranslate() {
  try {
    const result = await baiduTranslateBySuperagent('你好世界', 'auto', 'en');
    console.log('superagent翻译结果:', result.text);
  } catch (error) {
    console.error('superagent翻译失败:', error.message);
  }
}
优缺点
  • 优点:轻量小巧、语法简洁(链式调用)、支持流式响应、配置灵活;
  • 缺点:生态不如axios完善、拦截器功能需手动封装。
3. Apollo Client(GraphQL专用请求库)

针对GraphQL接口的专用请求库,提供数据缓存、查询优化、状态管理等功能,适用于GraphQL项目。

适用场景
  • 采用GraphQL接口的前端项目;
  • 需数据缓存、批量查询优化的场景。
核心示例(基础查询)
javascript 复制代码
import { ApolloClient, InMemoryCache, gql, useQuery } from '@apollo/client';

// 1. 创建Apollo Client实例
const client = new ApolloClient({
  uri: 'http://localhost:3000/graphql', // GraphQL接口地址
  cache: new InMemoryCache() // 内存缓存
});

// 2. 定义翻译查询
const TRANSLATE_QUERY = gql`
  query Translate($query: String!, $from: String, $to: String) {
    translate(query: $query, from: $from, to: $to) {
      text
      sourceText
      from
      to
      provider
    }
  }
`;

// 3. 组件中使用查询(React示例)
export function TranslateComponent({ query, from, to }) {
  const { loading, error, data } = useQuery(TRANSLATE_QUERY, {
    variables: { query, from, to }, // 查询变量
    fetchPolicy: 'cache-and-network' // 缓存策略
  });

  if (loading) return <div>翻译中...</div>;
  if (error) return <div>翻译失败:{error.message}</div>;

  return (
    <div>
      <p>原文:{data.translate.sourceText}</p>
      <p>译文:{data.translate.text}</p>
      <p>提供商:{data.translate.provider}</p>
    </div>
  );
}

// 4. 手动发起查询(非组件环境)
async function manualTranslate() {
  try {
    const result = await client.query({
      query: TRANSLATE_QUERY,
      variables: { query: '你好世界', from: 'auto', to: 'en' }
    });
    console.log('GraphQL翻译结果:', result.data.translate);
  } catch (error) {
    console.error('GraphQL查询失败:', error.message);
  }
}
优缺点
  • 优点:专为GraphQL设计、内置数据缓存、查询优化、支持订阅(实时数据);
  • 缺点:仅适用于GraphQL接口、学习成本较高、体积较大。

三、第三类:跨端/框架内置请求方式

这类方式适用于跨端框架(如uni-app、小程序),由框架内置提供,兼容多端运行环境。

1. uni.request(uni-app/小程序跨端请求)

uni-app框架内置的跨端请求API,兼容微信小程序、支付宝小程序、H5、App等多个平台。

适用场景
  • uni-app/微信小程序/支付宝小程序等跨端项目;
  • 需一次编写、多端运行的场景。
完整代码示例
javascript 复制代码
/**
 * uni-app跨端翻译请求
 * @param {string} query 待翻译文本
 * @param {string} from 源语言
 * @param {string} to 目标语言
 * @returns {Promise<Object>} 翻译结果
 */
export function baiduTranslateByUniRequest(query, from = 'auto', to = 'en') {
  return new Promise((resolve, reject) => {
    if (!query?.trim()) {
      reject(new Error('请传入有效的待翻译文本'));
      return;
    }

    uni.request({
      url: 'http://localhost:3000/api/translate/baidu', // 请求地址
      method: 'POST', // 请求方法
      header: {
        'Content-Type': 'application/json' // 请求头
      },
      data: { query, from, to }, // 请求体
      timeout: 8000, // 超时时间
      success: (res) => {
        const data = res.data;
        if (data.code !== 0) {
          reject(new Error(data.msg || '翻译失败'));
          return;
        }
        resolve(data.data);
      },
      fail: (err) => {
        const errorMsg = err.errMsg || 'uni.request请求失败';
        console.error(errorMsg);
        uni.showToast({
          title: errorMsg,
          icon: 'none'
        });
        reject(new Error(errorMsg));
      }
    });
  });
}

// 业务调用(uni-app组件中)
async function useUniRequestTranslate() {
  try {
    const result = await baiduTranslateByUniRequest('你好世界', 'auto', 'en');
    console.log('uni.request翻译结果:', result.text);
    uni.showToast({
      title: '翻译成功',
      icon: 'success'
    });
  } catch (error) {
    console.error('uni.request翻译失败:', error.message);
  }
}
2. wx.request(微信小程序专属请求)

微信小程序框架内置的请求API,仅适用于微信小程序环境。

适用场景
  • 纯微信小程序项目(非跨端);
  • 需调用微信小程序特有接口的场景。
核心示例
javascript 复制代码
/**
 * 微信小程序翻译请求
 * @param {string} query 待翻译文本
 * @param {string} from 源语言
 * @param {string} to 目标语言
 * @returns {Promise<Object>} 翻译结果
 */
export function baiduTranslateByWxRequest(query, from = 'auto', to = 'en') {
  return new Promise((resolve, reject) => {
    if (!query?.trim()) {
      reject(new Error('请传入有效的待翻译文本'));
      return;
    }

    wx.request({
      url: 'http://localhost:3000/api/translate/baidu',
      method: 'POST',
      header: {
        'Content-Type': 'application/json'
      },
      data: { query, from, to },
      timeout: 8000,
      success: (res) => {
        const data = res.data;
        if (data.code !== 0) {
          reject(new Error(data.msg || '翻译失败'));
          return;
        }
        resolve(data.data);
      },
      fail: (err) => {
        const errorMsg = err.errMsg || 'wx.request请求失败';
        console.error(errorMsg);
        wx.showToast({
          title: errorMsg,
          icon: 'none'
        });
        reject(new Error(errorMsg));
      }
    });
  });
}

四、第四类:特殊场景:代理转发(本地/生产环境)

这不是直接的请求方式,而是解决跨域和敏感信息保护的辅助方案,分为本地开发代理和生产环境代理。

1. Vite/Webpack本地代理

本地开发时,通过Vite/Webpack配置代理,将前端请求转发到后端,规避浏览器跨域限制。

Vite代理配置示例(vite.config.js)
javascript 复制代码
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    proxy: {
      // 匹配/api开头的请求,转发到后端
      '/api': {
        target: 'http://localhost:3000', // 后端服务地址
        changeOrigin: true, // 开启跨域模拟(修改请求头中的Host)
        rewrite: (path) => path, // 路径重写(无需修改路径可省略,如需去掉/api则写 path.replace(/^\/api/, ''))
        timeout: 10000 // 代理超时时间
      },
      // 单独配置WebSocket代理
      '/ws': {
        target: 'ws://localhost:3000',
        ws: true, // 开启WebSocket代理
        changeOrigin: true
      },
      // 配置SSE代理
      '/sse': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        headers: {
          'Accept': 'text/event-stream' // SSE响应头
        }
      }
    }
  }
});
配置后前端请求示例
javascript 复制代码
// 无需写完整后端地址,直接写/api开头
const result = await axios.post('/api/translate/baidu', { query, from, to });
2. 生产环境Nginx代理

生产环境中,通过Nginx反向代理,将前端请求转发到后端服务,解决跨域和域名暴露问题。

Nginx配置示例(nginx.conf)
nginx 复制代码
server {
  listen 80;
  server_name your-domain.com; # 你的前端域名

  # 前端静态资源目录
  root /usr/share/nginx/html;
  index index.html;

  # 解决Vue/React路由刷新404问题
  location / {
    try_files $uri $uri/ /index.html;
  }

  # 代理/api请求到后端
  location /api/ {
    proxy_pass http://127.0.0.1:3000/api/; # 后端服务地址
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_timeout 10s; # 代理超时时间
  }

  # 代理WebSocket请求
  location /ws/ {
    proxy_pass ws://127.0.0.1:3000/ws/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
  }

  # 代理SSE请求
  location /sse/ {
    proxy_pass http://127.0.0.1:3000/sse/;
    proxy_set_header Host $host;
    proxy_buffering off; # 关闭缓冲区,实时推送数据
    proxy_cache off;
    proxy_set_header Connection '';
    chunked_transfer_encoding on;
  }
}

五、各请求方式选型总结

请求方式 适用场景 推荐指数 核心优势
axios 现代前端项目(Vue/React等)、复杂请求配置 ★★★★★ 功能完善、拦截器、自动解析、生态丰富
fetch 现代浏览器、轻量无依赖场景 ★★★★☆ 原生无依赖、Promise化、语法简洁
XMLHttpRequest 老旧浏览器、精细控制请求流程 ★★★☆☆ 兼容性极强、支持进度监控
WebSocket 双向实时通信(聊天、协作) ★★★★☆ 实时性高、全双工通信
SSE 服务器单向实时推送(通知、监控) ★★★☆☆ 轻量、自动重连、基于HTTP
uni.request uni-app/小程序跨端项目 ★★★★☆ 跨端兼容、一次编写多端运行
Apollo Client GraphQL接口项目 ★★★★☆ 内置缓存、查询优化、支持订阅
superagent 中小型项目、追求轻量灵活 ★★★☆☆ 轻量小巧、链式调用
JSONP 老旧浏览器跨域(现已极少使用) ★★☆☆☆ 兼容老旧浏览器、无需后端CORS

六、核心注意事项(通用避坑指南)

  1. 跨域问题:本地开发用Vite/Webpack代理,生产环境用Nginx代理/后端CORS配置;
  2. 敏感信息保护:涉及appid/secretKey/token的请求,必须通过后端中转,前端不存储敏感信息;
  3. 异常处理:所有请求必须用try/catch捕获异常,区分网络错误、业务错误、超时错误;
  4. 超时控制:所有请求都应设置超时时间,避免前端长时间等待;
  5. 数据序列化:JSON请求需确保请求体序列化,响应体正确解析;
  6. 取消请求:组件销毁/页面跳转时,取消未完成的请求,避免内存泄漏。

以上就是前端访问服务的详细方法和补充方案,覆盖了绝大多数开发场景,可根据项目类型和需求选择合适的方式。

相关推荐
Zyx20072 小时前
Vue 3 实现 AI 流式输出(上篇):从用户体验说起
javascript
失败又激情的man2 小时前
爬虫逆向之阿里系cookie acw_sc__v2 逆向分析
前端·javascript·爬虫
小肖爱笑不爱笑2 小时前
Vue Ajax
前端·javascript·vue.js·web
四瓣纸鹤2 小时前
闭包到底是啥?
javascript·闭包
Moment2 小时前
一文搞懂 Tailwind CSS v4 主题变量映射背后的原理
前端·javascript·面试
我命由我123452 小时前
JavaScript WebGL - WebGL 引入(获取绘图上下文、获取最大支持纹理尺寸)
开发语言·前端·javascript·学习·ecmascript·学习方法·webgl
辛-夷2 小时前
2025年高频面试题整理(vue系列一)
前端·javascript·vue.js·前端框架
鹏多多3 小时前
一文搞懂柯里化:函数式编程技巧的解析和实践案例
前端·javascript·vue.js
Roc.Chang3 小时前
终极指南:解决 Vue 项目中 “regenerator-runtime/runtime“ 缺失报错
前端·javascript·vue.js·webpack·前端工程