阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 接口请求跨域问题

接口请求跨域问题

作者:陈川 阅读数:4653人阅读 分类: uni-app

跨域问题的本质

跨域问题源于浏览器的同源策略限制。同源策略要求协议、域名、端口三者完全相同才算同源。uni-app开发中,当应用请求不同源的接口时,浏览器会拦截响应数据。例如:

// 前端请求示例(会触发跨域)
uni.request({
  url: 'https://api.other-domain.com/data',
  success: (res) => {
    console.log(res.data)
  }
})

常见的解决方案

后端配置CORS

最规范的解决方式是在服务端设置Access-Control-Allow-Origin响应头:

// Spring Boot示例
@RestController
public class ApiController {
    @GetMapping("/data")
    public ResponseEntity<String> getData() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Access-Control-Allow-Origin", "*");
        return new ResponseEntity<>("response data", headers, HttpStatus.OK);
    }
}

代理服务器方案

在uni-app项目中配置vue.config.js实现开发环境代理:

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://api.target.com',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

实际请求时使用相对路径:

uni.request({
  url: '/api/userinfo',  // 实际转发到https://api.target.com/userinfo
  method: 'GET'
})

JSONP方案

适用于仅需GET请求的场景:

function jsonp(url, callbackName) {
  return new Promise((resolve) => {
    const script = document.createElement('script')
    script.src = `${url}?callback=${callbackName}`
    window[callbackName] = (data) => {
      resolve(data)
      document.body.removeChild(script)
      delete window[callbackName]
    }
    document.body.appendChild(script)
  })
}

// 使用示例
jsonp('https://api.example.com/data', 'handleData').then(data => {
  console.log(data)
})

uni-app特有的解决方案

使用条件编译

针对不同平台采用不同方案:

// #ifdef H5
// 浏览器环境使用代理
const baseURL = '/api'
// #endif

// #ifdef MP-WEIXIN
// 小程序环境使用完整URL
const baseURL = 'https://api.weixin.com'
// #endif

uni.request({
  url: baseURL + '/user/login'
})

配置manifest.json

对于微信小程序,需要在manifest.json中配置合法域名:

{
  "mp-weixin": {
    "appid": "",
    "cloud": true,
    "request": {
      "domainWhiteList": [
        "https://api.weixin.com"
      ]
    }
  }
}

生产环境部署方案

Nginx反向代理配置

server {
    listen 80;
    server_name yourdomain.com;

    location /api/ {
        proxy_pass https://api.backend.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        add_header Access-Control-Allow-Origin *;
    }
}

云函数中转方案

通过uni-cloud云函数转发请求:

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()

exports.main = async (event, context) => {
  const res = await cloud.callFunction({
    name: 'httpProxy',
    data: {
      url: 'https://api.target.com/data',
      method: 'POST',
      data: event.data
    }
  })
  return res.result
}

调试技巧与注意事项

Chrome禁用安全策略

开发时临时禁用同源策略(仅限本地调试):

# MacOS
open -n -a "Google Chrome" --args --disable-web-security --user-data-dir=/tmp/chrome

错误处理示例

完善的错误处理机制:

uni.request({
  url: 'https://api.example.com/data',
  timeout: 8000,
  fail: (err) => {
    if (err.errMsg.includes('timeout')) {
      uni.showToast({ title: '请求超时', icon: 'none' })
    } else if (err.statusCode === 404) {
      uni.showToast({ title: '接口不存在', icon: 'none' })
    } else {
      uni.showToast({ title: '网络错误', icon: 'none' })
    }
  }
})

特殊场景处理

文件上传跨域

需额外处理withCredentials:

uni.uploadFile({
  url: 'https://api.example.com/upload',
  filePath: tempFilePath,
  name: 'file',
  header: {
    'Content-Type': 'multipart/form-data'
  },
  withCredentials: true  // 需要携带cookie时设置
})

WebSocket跨域

WebSocket不受同源策略限制但受权限控制:

const socket = new WebSocket('wss://api.example.com/ws')

socket.onopen = () => {
  console.log('连接成功')
  socket.send(JSON.stringify({type: 'ping'}))
}

socket.onmessage = (e) => {
  console.log('收到消息:', e.data)
}

安全相关建议

敏感信息保护

避免在前端硬编码敏感信息:

// 不推荐
const API_KEY = '123456abcdef'

// 推荐通过后端接口获取
uni.request({
  url: '/getApiKey',
  success: (res) => {
    const key = res.data.key
    // 使用获取到的key
  }
})

HTTPS强制要求

现代浏览器对混合内容限制严格:

# 强制HTTPS
server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$host$request_uri;
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌