使用 Koa 做前端静态资源代理(搭建前端生产环境)

907 阅读4分钟

话不多说,直接开撸

本地前端项目初始化

这里以vue项目为例,本地如果已有vue-cli环境,可以直接使用vue-cli进行初始化项目,如是没有,请先安装:

npm install -g @vue/cli

然后使用vue-cli初始化项目

vue create my-project

这里创建项目时选手动选择包安装,要将 vue-router 选择安装上(后面要处理路由刷新的问题)

image.png

image.png 其他的默认就行了 安装完成之后,npm run serve 启动项目,本地环境就搭建好了

image.png

搭建node环境

静态文件代理

my-project 文件件下创建一个 server 文件夹,用来存放服务端代码。 我们在 server 文件夹下npm init -y 初始化一下(因为最终是要将此文件夹部署到服务器,所以要单独初始化一下)。然后我们新建一个 index.js文件,在这里我们写node 代码,然后再创建一个 static 文件夹,用来存放前端打包后的代码。

这里我们使用 koa 框架来实现。我们需要先安装几个插件

npm install koa koa-static -S

index.js里代码如下

const Koa = require('koa');
const path = require('path');
const app = new Koa();
const serve = require('koa-static');
// static就是存在前端打包好后的文件夹
app.use(serve(path.join(__dirname, '/static'), { extensions: ['html'] }));
app.listen(3000, () => {
  console.log('server is running, port is 3000');
}); 

这时候我们就可以去vue 项目中将打包地址改到 server/static 来测试一下。 vue.config.js 代码修改如下

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  outputDir: 'server/static', // 修改打包输出目录
})

然后执行npm run build进行打包。

image.png 这时候打包之后的代码就已放到 server 下面的 static 文件夹下了,这时候我们启动 index.js服务来看下效果。 在 server目录下执行

node index.js

image.png 这时候服务就启起来了,我们通过浏览器http://localhost:3000 就可以看到效果了

解决vue-router中mode为history时刷新页面Not Found的问题

我们安装 vue-router 的时候,mode 默认是history模式,在这个模式下,当我们路由切换到 about时再刷新页面,这个时候就会出现 not found 了

router.gif

在网上找了一个视频转 gif 的工具,转的有点糊,将就着看😂

这是因为单页面应用程序 (SPA) 通常使用一个 web 浏览器可以访问的索引文件,比如 index.html,然后,在 HTML5 History API 的帮助下(vue-router 的 history模式就是基于 History API 实现的),借助 JavaScript 处理应用程序中的导航。当用户单击刷新按钮或直接通过输入地址的方式访问页面时,会出现找不到页面的问题,因为这两种方式都绕开了 History API,而我们的请求又找不到后端对应的路由,页面返回 404 错误.

这个时候就需要另一个中间件来解决这个问题,connect-history-api-fallback

npm i connect-history-api-fallback -S

server/index.js 的修改如下

const Koa = require('koa');
const path = require('path');
const app = new Koa();
const serve = require('koa-static');

const history = require('connect-history-api-fallback');
const middleHistory = () => {
  const middleware = history();
  return async (ctx, next)=> {
    middleware(ctx, null, () => {});
    await next();
  };
};

app.use(middleHistory());

// static就是存在前端打包好后的文件夹
app.use(serve(path.join(__dirname, '/static'), { extensions: ['html'] }));

app.listen(3000, () => {
  console.log('server is running, port is 3000');
}); 

修改完成之后,重启一下服务node index.js,这是发现在 about 路由刷新的时候就好了。

另外,如果在前端工程中把vue-routermode改成hash也不会出现这种情况了

代理转发

平时的开发过程中,我们总要和后端进行接口联调,因为跨域的问题,我们需要在 vue.config.js中的devServer里设置 proxy 来做一层代理将请求转发到相应的服务上。那么在 koa 中又该怎么去设置呢。 这里我们使用koa2-proxy-middleware这个中间件来处理请求转发。

npm i koa2-proxy-middleware -S

例如,如果在vue.config.js中 设置了如下代理,将请求转发到http://127.0.0.1:9000

devServer: {
    proxy: {
      '/api': {
        target: 'http://127.0.0.1:9000',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }

那么在koa 中就要相应的设置如下转发

const proxy = require('koa2-proxy-middleware')
const options = {
  targets: {
    '/api/(.*)': {
      target: 'http://127.0.0.1:9000',
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      }
    },
  }
}

app.use(proxy(options));

最后 server/index.js中完整的代码如下

const Koa = require('koa');
const path = require('path');
const serve = require('koa-static');
const proxy = require('koa2-proxy-middleware')
const history = require('connect-history-api-fallback');
const app = new Koa();
const middleHistory = () => {
  const middleware = history();
  return async (ctx, next)=> {
    middleware(ctx, null, () => {});
    await next();
  };
};

const options = {
  targets: {
    '/api/(.*)': {
      target: 'http://127.0.0.1:9000',
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      }
    },
  }
}

app.use(middleHistory());
app.use(proxy(options));
// static就是存在前端打包好后的文件夹
app.use(serve(path.join(__dirname, '/static'), { extensions: ['html'] }));

app.listen(3000, () => {
  console.log('server is running, port is 3000');
});

然后部署的话,就把整个 server 文件夹放到服务器上,到 server 文件夹下启动服务,node index.js,就可以通过服务器ip:3000来访问了,这里推荐使用 pm2 来管理node进程,非常方便好用

代码

代码放到了 git 上github.com/photon12342…

增加了一个 service 目录,写了一个简单的接口,用来测试代理问题