• 跨域实例和解决方案


    跨域实例和解决方案

    以下我们用 nodejs 演示了一个 http 服务, 接口为 http://localhost:8000/ .如果正常连接成功, 则会返回文本 ok .

    然后以 js 在浏览器中进行 fetch 进行请求测试, 演示各种形式的跨域, 以及对应的解决方式, 所有代码都是可运行的实例.

    服务端代码, 默认没有跨域

    const http = require('http');
    const server = http.createServer((req, res) => {
      res.writeHead(200, {
        'x-age': '18',
      });
      res.end('ok');
    });
    server.listen(8000, () => console.log(`启动成功 http://localhost:8000`));
    

    客户端代码报错以及对应的设置方式

    /**
    简单请求
      await fetch('http://localhost:8000/api/test').then(res => res.text())
    报错
      Access to fetch at 'http://localhost:8000/api/test' from origin 'http://localhost:9005' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
    设置响应头
      'Access-Control-Allow-Origin': '*'
     */
    
    /**
    自定义请求头
      await fetch('http://localhost:8000/api/test ', {
        headers: { 'Content-Type': 'application/json' },
      }).then(res => res.text())
    错误
      Access to fetch at 'http://localhost:8000/api/test' from origin 'http://localhost:9005' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
    设置响应头
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Headers': '*',
     */
    
    /**
    自定义方法
      await fetch('http://localhost:8000/api/test ', {
        method: 'PATCH',
      }).then(res => res.text())
    错误
      Access to fetch at 'http://localhost:8000/api/test' from origin 'http://localhost:9005' has been blocked by CORS policy: Method PATCH is not allowed by Access-Control-Allow-Methods in preflight response.
    设置响应头
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': '*',
     */
    
    
    /**
    携带 cookie
      await fetch('http://localhost:8000/api/test', {
        credentials: 'include',
      }).then(res => res.text())
    报错
      Access to fetch at 'http://localhost:8000/api/test' from origin 'http://localhost:9005' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
      Access to fetch at 'http://localhost:8000/api/test' from origin 'http://localhost:9005' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
    设置响应头
      'Access-Control-Allow-Origin': 'http://localhost:9005',
      'Access-Control-Allow-Credentials': 'true',
     */
    
    
    /**
    设置自定义 header
      await fetch('http://localhost:8000/api/test', {
        headers: { 'x-age': '28' },
      }).then(res => res.text())
    报错
      Access to fetch at 'http://localhost:8000/api/test' from origin 'http://localhost:9005' has been blocked by CORS policy: Request header field x-age is not allowed by Access-Control-Allow-Headers in preflight response.
    设置响应头
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Headers': '*',
     */
    
    
    /**
    读取自定义 header
      await fetch('http://localhost:8000/api/test').then(res => res.headers.get('x-age'))
    报错
      无, 但不能读取到 header 中的 x-age
    设置响应头, 表明允许获取的自定义头
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Expose-Headers': 'x-age',
     */
    
    /**
    综合测试
      await fetch('http://localhost:8000/api/test', {
        method: 'PATCH',
        credentials: 'include',
        headers: { 'x-age': '28' },
        body: JSON.stringify({
          token: 'test_token',
          content: 'test_content'
        })
      }).then(async res => ({text: await res.text(), age: res.headers.get('x-age')}))
     */
    
    

    总结

    是否可以跨域, 是由服务器端决定的. 通常设置响应头即可, 在响应头中告诉浏览器允许跨域的域名, 以及允许跨域的方式, 还有允许读取和设置的请求头, 全都由服务端决定.

    一般我们有几种解决方案:

    • 关闭浏览器的安全策略
    • 安装浏览器插件
    • 直接从后端代码上设置为允许
    • 使用代理方式

    其中插件的方式和代理的方式其他都是在中途拦截并设置 header 为对应的跨域标致.

    在前端项目的开发环境中, 一般可以使用 webpack 的 proxy 功能, 或者可以使用 mockm 的 proxy 功能. 推荐 mockm, 因为它不仅可以代理, 并且不需要复杂的配置, 还能获取到请求的接口历史和数据.

  • 相关阅读:
    Convolution1D与Convolution2D区别
    git
    cast函数
    Ubuntu14.04编译WebRTC For Android代码 2014-07-24
    R语言基础-数组和列表
    疯狂的创业运动
    Autodesk 举办的 Revit 2015 二次开发速成( 1.5 天),教室培训, 地点武汉
    注冊(十一)重注冊带有鉴权信息
    ubuntu14.04无法安装Curl
    Bash脚本中的操作符
  • 原文地址:https://www.cnblogs.com/daysme/p/14698118.html
Copyright © 2020-2023  润新知