面试会问的 history路由跟反向代理解决跨域的问题

本文深入探讨了历史模式路由的工作原理,展示了如何使用history.pushState在不刷新页面的情况下改变URL,并同步切换组件显示与隐藏,同时提供了hash模式的对比说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. history模式路由是怎么实现的吗

    history模式路由利用history.pushState改变URL,但并不会刷新页面的原理; 并在改变URL同时切换组件 的显示/隐藏。

    history模式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="div">
      <a href="/home">home</a>
      <a href="/about">about</a>
      <a href="/other">other</a>
    </div>
    <!-- 切换路由,显示不同内容 -->
    <div class="route"></div>

    <script>
      const aEles = document.querySelectorAll('#div>a')
      const route = document.querySelector('.route')

      aEles.forEach(item => {
        item.onclick = function (e) {
          e.preventDefault()
          // 切换不同path,显示不同组件(内容)
          route.innerHTML = map.get(item.getAttribute('href'))
          // 改变URL,但并不会发请求到浏览器
          //参数1,状态对象,相当于是路由的param,附加信息。
          //参数2,可以忽略
          //参数3 新的URL
          history.pushState(
            { id: route.innerHTML },
            '',
            item.getAttribute('href')
          )
        }
      })

      const map = new Map([
        ['/home', '我是home'],
        ['/about', '我是about'],
        ['/other', '我是other']
      ])

      //浏览器前进后退的支持,
      // history.back()、history.forward()、history.go()
      window.onpopstate = function (ev) {
        console.log(ev)
        route.innerHTML = ev.state.id
      }
    </script>
  </body>
</html>

hash模式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <a href="#/home">home</a>
      <a href="#/about">about</a>
      <a href="#/other">other</a>

      <div id="route"></div>
    </div>
  </body>

  <script>
    const route = document.querySelector("#route")

    window.onhashchange = function () {
      const map = new Map([
        ["#/home", "我是home"],
        ["#/about", "我是about"],
        ["#/other", "我是other"],
      ])
      route.innerHTML = map.get(location.hash)
    }
  </script>
</html>

2.反向代理解决跨域的问题

var http = require('http')

http.createServer(function (request, response) {
    // 设置允许跨域的域名,*代表允许任意域名跨域
    response.setHeader('Access-Control-Allow-Origin', '*') //允许的header类型
    response.setHeader('Access-Control-Allow-Headers', 'Content-type') //跨域允许的请求方式
    response.setHeader(
      'Access-Control-Allow-Methods',
      'PUT,POST,GET,DELETE,OPTIONS,PATCH'
    ) //可选,用来指定本次预检请求的有效期,单位为秒。在此期间,不用发出另一条预检请求。
    response.writeHead(200, { 'Content-Type': 'application/json' })

    // 代理请求目标服务器的数据
    getTargetServerData().then(data => {
      // 发送响应数据 "Hello World"
      response.end(data)
    })
}).listen(8888)

// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/')

// 代理请求目标服务器的数据
function getTargetServerData () {
  var options = {
    host: '129.211.82.55',
    port: 3000,
    path: '/api/home/swipers',
    method: 'GET'
  }

  var body = ''
  return new Promise((resolve, reject) => {
    var req = http.request(options, function (res) {
        res.on('data', function (data) {
            body += data
        }).on('end', function () {
            resolve(body)
          })
      }).on('error', function (e) {
         reject(e)
      })
    req.end()
  })
}
  1. 如何配置webpack的代理

    1. 一般前端项目启动在localhost:8080, 联调需要访问不同环境的服务器,如果服务器恰好没有设置CORS,那么就会跨域。反向代理可以解决跨域问题,前端访问代理服务器,代理服务访问目标服务器,由于服务器访问服务器是不是跨域的,所以前端也就可以正常获取了请求数据。最常见的反向代理服务器就是Webpack Server, 配置webpack代理,匹配成功的请求的URL,webpack代理服务器访问target服务器,返回请求

      proxy: {
          // 请求/api/home/swipers时,实际上是在请求http://129.211.82.55:3000/api/home/swipers
          '/api': {
              target: 'http://129.211.82.55:3000'
          }
      }
      

在这里插入图片描述

### 解决问题的方案 在开发前端项目时,问题是一个常见的挑战。对于Codewhy弘源后台这样的项目,可以通过以下几种方式来解决问题: #### 1. **后端配置 CORS(资源共享)** CORS 是一种标准的解决方案,允许服务器明确指定哪些来源可以访资源。通过在后端设置 CORS 头部信息,可以解决问题。例如,在 Node.js 的 Express 框架中,可以使用 `cors` 中间件[^1]。 ```javascript const express = require('express'); const cors = require('cors'); const app = express(); app.use(cors()); app.get('/data', (req, res) => { res.json({ message: 'This is data from the backend.' }); }); app.listen(3000, () => { console.log('Server is running on port 3000'); }); ``` #### 2. **前端代理配置** 如果后端无法直接修改 CORS 配置,可以在开发环境中使用 Webpack 的代理功能。Webpack 提供了 `devServer.proxy` 配置项,可以将请求转发到目标服务器,从而避免问题。 ```javascript module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:3000', // 后端接口地址 changeOrigin: true, pathRewrite: { '^/api': '' } } } } }; ``` #### 3. **JSONP 方式** JSONP 是一种较老的解决方案,适用于只支持 GET 请求的场景。它通过 `<script>` 标签动态加载数据,但由于安全性较低且不支持复杂请求类型,通常不推荐使用。 #### 4. **使用 Nginx 反向代理** 在生产环境中,可以通过 Nginx 配置反向代理解决问题。Nginx 将前端请求转发到后端服务,从而绕过浏览器的同源策略限制。 ```nginx server { listen 80; server_name yourdomain.com; location /api/ { proxy_pass http://localhost:3000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } ``` #### 5. **调整 Vue Router 的模式** 如果使用 Vue Router 的 `history` 模式,可能会遇到路径重定向导致的问题。在这种情况下,确保后端正确配置了路由规则,或者切换为 `hash` 模式以避免路径冲突。 ```javascript const router = VueRouter.createRouter({ history: VueRouter.createWebHistory(), routes: [...] }); ``` 切换为 `hash` 模式: ```javascript const router = VueRouter.createRouter({ history: VueRouter.createWebHashHistory(), routes: [...] }); ``` ### 注意事项 - 确保前后端的环境配置一致,尤其是在开发和生产环境中。 - 使用代理或反向代理时,注意路径映射的正确性[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值