nodejs解决跨域三种方式(jsonp/cors/代理)

754 阅读4分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

解决跨域问题

  • js 利用浏览器请求不跨域的特性来请求数据 浏览器中可以请求另一个平台下的 js css 是不受限制的 但是通过 ajax 请求接口地址 就会受到限制

jsonp

  • 这里是后台搭建的服务器 通过另一台服务器向该服务器请求 测试跨域问题
  • const http = require('http')
    const url = require('url')
    ​
    const server = http.createServer((req, res) => {
        let urlStr = req.url
        console.log(urlStr)
        let urlObj = url.parse(urlStr, true)
        console.log(urlObj)
        switch (urlObj.pathname) {
            case '/api/data':
                // res.write('hello')
                // 后端写什么代码 注入到浏览器就运行了 写js代码能识别
                res.write('getData("hello")')
                break;
            default:
                res.write('page not found.')
        }
        res.end()
    })
    ​
    server.listen(8080, () => {
        console.log('localhost:8080')
    })
    
  • 这里报了一个错误 记录一下

    • 在js中出现下面的错误:

      Uncaught SyntaxError: Unexpected identifier可能的原因是:
              1.有可能是字符串类型的,但是并没有加双引号。
              2.有的是没有加逗号 “,”仔细检查便好。
              3.如果是jsp的话仔细检查下js中的声明,int与var不同!
              4.有的是{}与()的区别。如:Code:{"#code"},改成 Code:("#code"),即可 
              5.我犯得 /api 写成了 ./api
      
  • 请求一个自己本地搭建的服务 使用 script 去请求的话是不跨域的 这是一种解决跨域的方式 可以使用这个请求第三方的源 像 jquery vue 都唔那个通过这个请求 初学者一般都是使用这个来练习语的

  • 使用 http-server 可以启动服务

    npx http-server -p 9000 // 端口号

    npx 的作用是调用内置模块 可以临时下载这个包使用 下次使用又会重新下载

    可以使用 这个 9000 的服务器去请求 后台搭建的 8080 测试跨域问题

  • <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=  device-width, initial-scale=1.0">
        <title>Document</title>
        <!-- 解决 请求不到 图标问题 -->
        <link rel="shortcut icon" href="#"/>
    </head>
    <body>
        <script>
            function getData(data) {
                console.log(data)
            }
        </script>
        <script src="http://localhost:8080/api/data?cb=getData"></script>
    </body>
    </html>
    

cors

  • 另一种启动服务的方式 可以使用浏览器自带的 fetch 方法
  • <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>CORS</title>
        <link rel="shortcut icon" href="#"/>
    </head>
    <body>
        <script>
            <!-- 浏览器默认的请求 -->
            fetch('http://localhost:8080/api/data')
            .then(response => response.json())
            .then(result => {
                console.log(result)
            })
        </script>
    </body>
    </html>
    
  • /* 
        这里是后台搭建的服务器
        通过另一台服务器向该服务器请求 测试跨域问题
    ​
    */
    const http = require('http')
    const url = require('url')
    const server = http.createServer((req, res) => {
        let urlStr = req.url
        console.log(urlStr)
        let urlObj = url.parse(urlStr, true)
        console.log(urlObj)
        switch (urlObj.pathname) {
            case '/api/data':
                res.writeHead(200, {
                    'content-type': 'application/json',
                    // 加上下面这行代码解决跨域 cors
                    'Access-Control-Allow-Origin': '*'
                })
                res.write('{"ret": true, "data": "hello"}')
                break;
            default:
                res.write('page not found.')
        }
        res.end()
    })
    ​
    server.listen(8080, () => {
        console.log('localhost:8080')
    })
    

设置代理

  • 使用 proxy 中间件

  • 需要安装包

    • npm http-proxy-middleware -D
      
  • 需要请求的地址

    • http://you.163.com/xhr/search/queryHotKeyWord.json?__timestamp=1637911962810
      
  • 实际测试的地址

    • http://localhost:8080/xhr/search/queryHotKeyWord.json?__timestamp=1637911962810
      
  • 代码实现 示例1

    • 引入相应的模块 对 /xhr 做判断 取自上面的接口地址 you.163.com
    • 如果在请求地址中识别到 /xhr 则通过中间件代理
    • 就会将 http://localhost:8080/xhr/search/queryHotKeyWord.json?__timestamp=1637911962810 装换成 you.163.com/xhr/search/… 去请求
    • const http = require('http')
      const url = require('url')
      const { createProxyMiddleware } = require('http-proxy-middleware')
      ​
      const server = http.createServer((req, res) => {
          const urlStr = req.url
          // console.log(urlStr)
          if (//xhr/.test(urlStr)) {
              // console.log(urlStr)
              const proxy = createProxyMiddleware('/xhr', {
                  target: 'http://you.163.com',
                  changeOrigin: true
              })
              proxy(req, res)
          } else {
              console.log('error')
          }
      })
      ​
      ​
      server.listen(8080, () => {
          console.log('localhost:8080')
      })
      

    image.png

    • 该方法是基础讲解 有一个弊端就是 /xhr 是在原链接上的 这样的方法并不通用 必须得识别所有链接才行
  • 示例2

    • 我们可以自己定义一个路径作为识别标志 之后请求地址时在原地址的基础上加上这个识别标识就能识别所有地址了 但是这个存在一个问题 因为加上了 自己定义的 /api 这样地址就改变了 没有办法请求到数据 解决方法就是重新拼接地址 将 /api 提环成 '' 空字符串

    • const http = require('http')
      const url = require('url')
      const { createProxyMiddleware } = require('http-proxy-middleware')
      ​
      const server = http.createServer((req, res) => {
          const urlStr = req.url
          // console.log(urlStr)
          if (//xhr/.test(urlStr)) {
              // console.log(urlStr)
              const proxy = createProxyMiddleware('/xhr', {
                  target: 'http://you.163.com',
                  changeOrigin: true
              })
              proxy(req, res)
          }else if(//api/.test(urlStr)) {
              // https://www.lagou.com/wn/jobs?px=new&pn=1&kd=%E9%94%80%E5%94%AE%E4%B8%93%E5%91%98&city=%E4%B8%8A%E6%B5%B7&district=%E6%B5%A6%E4%B8%9C%E6%96%B0%E5%8C%BA
              const proxy2 = createProxyMiddleware('/api', {
                  target: 'https://www.lagou.com',
                  changeOrigin: true,
                  pathRewrite: {
                      '^/api': ''
                  }
              })
              proxy2(req, res)
          } else {
              console.log('error')
          }
      })
      ​
      ​
      server.listen(8080, () => {
          console.log('localhost:8080')
      })
      
    • 过程分析

image.png

  • 代理的原理 就相当于 找中介帮你去办事 上例中本地服务器就是代理 通过本地服务器去向接口地址发起请求解决跨域