Node.js 基础篇(五):内置对象 http / https(2)跨域

同源策略会隔离不同源的 DOM、页面数据和网络通信,进而实现 Web 页面的安全性。但很多时候我们需要跨域资源共享进行安全地跨域操作,下面我们讲解目前主要采用的几种解决跨域的方式

  • 通过 jsonp 跨域
  • 跨域资源共享(CORS)
  • 中间件代理跨域

通过 jsonp 跨域

Jsonp(JSON with Padding (填充))

通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

前端代码示例:index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>jsonp</title>
</head>
<body>
<h1>通过jsonp跨域</h1>
<script>
  const script = document.createElement('script');
  script.type = 'text/javascript';

  // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
  script.src = 'http://localhost:8080/getUserInfo?userId=1&callback=handleCallback';
  document.head.appendChild(script);

  // 回调执行函数
  function handleCallback(res) {
    console.log(res);
  }
</script>
</body>
</html>

执行 npx http-server --port=9000启动服务


后端 node.js 代码示例:server.js

const http = require('http')
const url = require('url')

const server = http.createServer((request, response) => {
  const urlObj = url.parse(request.url, true)
  console.log(urlObj);

  switch (urlObj.pathname) {
    case '/getUserInfo':
      const data = {
        name: '张三',
        id: '1',
        sex: '男',
      }
      // 这里用函数包裹数据作为响应数据就是 Padding(填充)
      response.end(`${urlObj.query.callback}(${JSON.stringify(data)})`)
      break
    default:
      response.end('404.')
      break
  }
})

server.listen(8080, () => {
  console.log('localhost:8080');
})

执行 node server.js可以看到 jsonp 跨域成功
在这里插入图片描述

跨域资源共享(CORS)

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。

需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。

目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

前端代码示例:index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>跨域资源共享CORS</title>
</head>
<body>
<h1>跨域资源共享CORS</h1>
<script>
  fetch('http://localhost:8080/getUserInfo', {
    credentials: 'include', // 前端跨域携带cookie
  })
  .then(response => response.json())
  .then(res => {
    console.log(res);
  })
</script>
</body>
</html>

执行 npx http-server --port=9000启动服务


后端 node.js 代码示例:server.js

若后端设置成功,前端浏览器控制台则不会出现跨域报错信息,反之,说明没设成功。

const http = require('http')
const url = require('url')

const server = http.createServer((request, response) => {
  const urlObj = url.parse(request.url, true)

  let data = ''
  request.on('data', (chunk) => {
    data += chunk
  })

  request.on('end', () => {
    switch (urlObj.pathname) {
      case '/getUserInfo':
        const data = {
          name: '张三',
          id: '1',
          sex: '男',
        }
        response.writeHead(200, {
          'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
          'Access-Control-Allow-Origin': 'http://127.0.0.1:9000', // 允许访问的域(协议+域名+端口)
          /*
           * 此处设置的cookie还是 localhost:8080 的而非 127.0.0.1:9000,因为后端也不能跨域写cookie(nginx反向代理可以实现),
           * 但只要 localhost:8080 中写入一次cookie认证,后面的跨域接口都能从 localhost:8080 中获取cookie,从而实现所有的接口都能跨域访问
           */
          'Set-Cookie': 'l=a123456;Path=/;Domain=localhost:8080;HttpOnly',  // HttpOnly的作用是让js无法读取cookie
          'Content-Type': 'application/json;charset=utf-8'
        })
        response.end(JSON.stringify(data))
        break
      default:
        response.end('404.')
        break
    }
  })
})

server.listen(8080, () => {
  console.log('localhost:8080');
})

执行 node server.js可以看到 cors 跨域成功
在这里插入图片描述

中间件代理跨域

Node.js中间件实现跨域代理,是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。

前端代码示例:index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>中间件代理跨域</title>
</head>
<body>
<h1>中间件代理跨域</h1>
<script>
  fetch('http://localhost:8080/api/community/home-api/v1/get-tab-total?username=qq_41887214', {
    credentials: 'include', // 前端跨域携带cookie
  })
  .then(response => response.json())
  .then(res => {
    console.log(res);
  })
</script>
</body>
</html>

执行 npx http-server --port=9000启动服务


后端 node.js 代码示例:server.js

const http = require('http')
const url = require('url')
const { createProxyMiddleware } = require('http-proxy-middleware')

const server = http.createServer((request, response) => {
  if (/^\/api/.test(request.url)) {
    const apiProxy = createProxyMiddleware('/api', {
      // 代理跨域目标接口
      target: 'https://blog.csdn.net',
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      },
      // 修改响应头信息,实现跨域并允许带cookie
      onProxyRes: function(proxyRes, req, res) {
        proxyRes.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:9000'; // 允许访问的域(协议+域名+端口)
        proxyRes.headers['Access-Control-Allow-Credentials'] = 'true'; // 后端允许发送Cookie
        proxyRes.headers['Content-Type'] = 'application/json;charset=utf-8';
      },

      // 修改响应信息中的 cookie Domain
      cookieDomainRewrite: 'http://127.0.0.1:9000'  // 可以为false,表示不修改;如下:
      // set-cookie: uuid_tt_dd=10_18756827270-1644377109020-376532; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net;
      // set-cookie: uuid_tt_dd=10_18756827270-1644377157391-106781; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=http://127.0.0.1:9000;
    })
    apiProxy(request, response)
  } else {
    switch (url) {
      case '/index.html':
        response.end('index.html')
        break
      case '/search.html':
        response.end('search.html')
        break
      default:
        response.end('404.')
    }
  }
})

server.listen(8080, () => {
  console.log('localhost:8080');
})

执行 node server.js可以看到 代理 跨域成功
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__畫戟__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值