node代理解决本地开发跨域问题

4,969 阅读4分钟

背景

跨域:指的是浏览器不能执行其它网站的脚本。它是由浏览器的同源策源引起的,是浏览器对 JavaScript 施加的安全限制。

        在前后分离的开发过程中,由于静态资源在本地,而api接口在另一台服务上,我们经常会使用localhost或者IP的方式去访问另一台服务器的api接口,这就会产生跨域问题。

        对于由webpack构建的项目在开发环境解决跨域很方便,直接修改webpack的代理配置就可以。而对于一些由jq构建或者原生的项目则无法通过这种方式解决。本文记录一下如何通过node启动一个代理服务解决这类项目的开发环境跨域问题。

准备工作

        首先我们先来创建一个jq项目,项目包含html和页面加载的css,jshtml内通过ajax访问接口。

WX20210829-194320@2x.png

        let baseUrl = "http://localhost:8082"
        function getList() {
            $.ajax({
                type: "post",
                headers: {
                    "Content-Type": "application/json;charset=UTF-8",
                    "Authorization": "b889e2f9-9720-4d93-a798-f63e9cbfd7f0"
                },
                url: baseUrl + "/api/getList",
                data: JSON.stringify({ "pageNum": 1, "pageSize": 10, "type": 0 }),
                dataType: "json",
                success: res => {
                    console.log(res)
                }
            })
        }
        getList()

这里模拟了一下项目里的ajax配置,携带了验权信息以及参数,我将后端的api服务运行在本地的8082端口上,不同环境的api地址可以修改baseUrl。这时候打开index.html发现页面抛出了一个跨域错误,至此,我们就模拟出了一个跨域的jq项目。

手撸代码

1.创建node项目

环境基于 node: v12.13.1、 webpack: v3.6.0

jq-project的同级目录下执行npm init命令,一路回车,会得到一个默认配置的package.json文件:

{
  "name": "init",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

同级目录下创建index.js文件名要与package.json中的main指向的文件名一致,安装expressnodemon插件,创建一个简单的node服务监听3000端口。

npm i express nodemon
  • express是一个node.js Web框架,可以使项目更轻快灵活;
  • nodemon是一个实现node.js热更新的插件,保存时就可以更新js文件;
let express = require('express');
let app = express()
app.listen(3000,()=>{
    console.log("server running at http://localhost:3000")
})

package.json添加一条启动命令,npm start 启动服务,控制台输出server running at http://localhost:3000即为启动成功。

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon index.js"
  },

2.通过node服务访问html

jq-project下的静态资源通过express托管,这样通过http://localhost:3000/index.html就可以访问到jq-project下的资源。

app.use('/', express.static('jq-project'))
  • express.static(root, [options])express内置的中间件,可以托管静态资源.如:

    1.app.use('/', express.static('jq-project'))可以通过http://localhost:3000/index.htmlhttp://localhost:3000/js/jquery.min.js访问到资源。

    2.app.use('/static', express.static('jq-project'))可以通过http://localhost:3000/static/index.htmlhttp://localhost:3000/static/js/jquery.min.js访问到资源。

3.配置代理

http-proxy-middleware是一个实现代理的中间件。webpack也是使用这个插件实现代理的,所以它的配置跟webpack代理配置一致。

代理原理示意:

npm i http-proxy-middleware
let express = require('express');
let app = express()
let { createProxyMiddleware } = require('http-proxy-middleware');
const options = {
    target: 'http://localhost:8082',
    changeOrigin: true,
    ws: true,
    secure: true,
    pathRewrite: {
        '/api': '/api',
    },
};
app.use('/', express.static('jq-project'))
app.use('/api', createProxyMiddleware(options));
app.listen(3000,()=>{
    console.log("server running at http://localhost:3000'")
})
  • target:要代理到的服务器,可以是域名也可以是ip+端口号;
  • changeOrigin:虚拟托管网站,如果为true,8082端口服务端获取的请求headers中请求来源是3000端口服务器.如果为false,获取的请求headers中请求来源是8082端口服务器;
  • ws:是否代理websockets;
  • secure:是否代理https请求;
  • pathRewrite:重写路径,将":"前的路径替换为后面的路径;

4.请求代理服务

修改html中的ajax请求,将请求的url改为代理服务器。刷新页面,成功的拿到数据。

baseUrl = "http://localhost:3000"

结尾

        解决跨域的方法有很多,这种方式是我比较热衷的一种方式,几行代码就可以实现,也不用麻烦后端或者运维去修改服务器的配置,自给自足。当有新的项目只需要再声明一个代理就可以,十分方便。