zoukankan      html  css  js  c++  java
  • 跨域详解及其常见的解决方式

    跨域是什么

    跨域是一个域下的网页去请求另一个域下的资源。严格点来说就是两个域的协议、域名、端口任何一个不同时,都会被当作跨域。当跨域访问资源时,会受到浏览器的安全限制,详细的情况可以看下表:

    URL 说明 是否允许通信
    http://www.a.com/a.js
    http://www.a.com/b.js
    同一域名 允许
    http://www.a.com/a/a.js
    http://www.a.com/b/b.js
    同一域名,不同文件夹 允许
    http://www.a.com:3000/a.js
    http://www.a.com/b.js
    同一域名,不同端口 不允许
    http://www.a.com/a.js
    https://www.a.com/b.js
    同一域名,不同协议 不允许
    http://www.a.com/a.js
    http://70.32.92.74/b.js
    域名和域名对应IP 不允许
    http://www.a.com/a.js
    http://script.a.com/b.js
    主域相同,子域不同 不允许
    http://www.a.com/a.js
    http://a.com/b.js
    同一域名,不同二级域名(同上) 不允许
    http://www.cnblogs.com/a.js
    http://www.a.com/b.js
    不同域名 不允许

    为什么限制跨域访问资源

    浏览器限制跨域访问资源是一种安全策略,可以预防某些恶意行为。浏览器在每次发起请求时都会带上cookie,试想下,如果没有这总安全策略,evil.com也会拿到用户在secure.comcookieevil.com利用cookie里的信息登录用户的账号,这样用户的数据就被泄露了。跨域限制就是为了避免这种情况的发生。

    跨域资源的几种访问方式

    • jsonp

      原理:jsonp之所以能够实现跨域资源的访问,是因为<script>标签不受浏览器同源策略的限制,使用时将src属性指定一个跨域URL,服务器在收到请求后,将数据放到指定的callback里传回来。

      实现:

      前端部分:
      function fetchjsonp(res) {
        console.log(res) // 可以获得服务端的数据,{data: "json data"}
      }
      const script = document.createElement('script')
      script.src = 'http://127.0.0.1:8080?callback=fetchjsonp'
      document.head.appendChild(script)
      服务端:
      const http = require('http');
      const hostname = '127.0.0.1';
      const port = 8080;
      const server = http.createServer((req, res) => {
        if (~req.url.indexOf('?callback')) { // 简单处理 JSONP 跨域的时候
          const obj = {
            "data": 'json data',
          }
          const callback = req.url.split('callback=')[1]
          const jsonData = callback + `(${JSON.stringify(obj)})`
          res.end(jsonData) // 这里最终返回前端的是相当于调用函数 callback({json})
        } else { // 非跨域的时候
          res.statusCode = 200
          res.setHeader('Content-Type', 'text/plain')
          res.end('not jsonp
      ')
        }
      });
      server.listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`);
      });
      

      优缺点:jsonp优点是兼容性好,支持低版本的浏览器跨域访问。缺点是只支持get请求,不容易判断请求是否失败。

    • CORS

      原理:CORS(cross-origin-resource-sharing)跨域资源共享,其思想是使用自定义的HTTP头部,让浏览器域服务器进行沟通,从而决定请求或响应是成功还是失败。服务器端一般在Access-Control-Allow-Origin中指定对应的域,当浏览器访问对应的资源。
      实现:

      前端部分:
      axios.get('http://127.0.0.1:8080/').then(res => {
        console.log(res) // data from cors
      })
      服务端:
      const http = require('http')
      const hostname = '127.0.0.1'
      const port = 8080
      const server = http.createServer((req, res) => {
        res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:3000') // 设置请求源
        res.setHeader('Access-Control-Allow-Methods', 'get') // 设置请求方法
        res.end('data from cors')
      })
      server.listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`)
      })
      

      优缺点:优点是支持所有的HTTP请求方法,缺点是不支持老的浏览器;

    • 使用代理

      原理:上面我们已经说了,浏览器的跨域限制是发生在浏览器里的,服务器端是没有的,所以可以使用服务器代理请求其他域的资源,然后在返回给客户端。

      实现:比如说浏览器直接访问http://127.0.0.1:8080会被限制,那么我们可以使用node作代理,来获取http://127.0.0.1:8080返回的资源。

      前端部分:
      axios.get('http://127.0.0.1:8000/').then(res => {
        console.log(res)
      })
      node代理:
      const express = require('express')
      const request = require('request')
      const app = express()
      app.use('/', function (req, res) {
        res.set('Access-Control-Allow-Origin', '*')
        const url = 'http://127.0.0.1:8080' // 代理的URL
        req.pipe(request(url)).pipe(res)  
      })
      app.listen(process.env.PORT || 8000)
      
    • 使用WebSocket

      原理:WebSocketHTML5的协议,可以让浏览器与服务器之间建立一个全双工、双向通信。当浏览器使用websocket与服务器建立连接后,HTTP协议会变成websocket协议,websocket协议是不受同源策略限制的,所以可以实现跨域请求资源;

      实现:

      前端部分:
      const ws = new WebSocket("ws://127.0.0.1:8080")
      ws.onopen = function (e) {
        console.log('Connection to server opened')
      }
      ws.onmessage = function (event) {
        console.log('Client received a message: ', event.data) // 客户端接受的数据在 event.data 中
      }
      服务端:
      const WebSocketServer = require('ws').Server
      const  ws = new WebSocketServer({ port: 8080 })
      ws.on('connection', (ws) => {
        ws.send('hello websocket') // websocket 发送给客户端的数据
      })
      
  • 相关阅读:
    vue
    Html5的本地储存 Web Storage
    java json解析(转)
    Python常用字符编码(转)
    特殊符号集锦(转)
    neo4j性能调优(转)
    hadoop fs -text和hadoop fs -cat的区别(转)
    docker和dockerfile极简入门(转)
    docker原理(转)
    neo4j配置(转)
  • 原文地址:https://www.cnblogs.com/yangrenmu/p/10548043.html
Copyright © 2011-2022 走看看