浅谈node结合express第三方插件使用跨域

本文详细介绍了在Node.js中实现跨域的多种方法,包括CORS、JSONP及服务器反向代理,同时提供了爬虫技术的基本原理与实践案例。

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

node实现跨域

1:CORS实现跨域 => 使用把跨域的.js文件在中间件中定义(函数),然后导出这个中间件!

CORS实现跨域

  • 创建一个服务器
const express = require("express");

//引入端口号
const {
  PORT
} = require("./config.json")

//引入路由目录下的所有路由 => 就是在index.js文件中导出了一个中间件函数!
const Router = require("./router");

//创建一个服务器
const app = express();

//使用中间件 来把静态资源对外的开发
app.use(Router);


//服务器监听端口号
app.listen(PORT, () => {
  console.log(`server is running ${PORT}`);
})
  • index.js文件!
const express = require("express");

//创建一个路由对象! 作用:就是在index.js文件之中  根据不同的接口划分为不同的接口路由!
const router = express.Router();
const cors = require("../filter/cors");
router.use(cors)

//对于中间件的格式化 路径和json数据
router.use(express.json(), express.urlencoded());

//引入 goods和 user的接口!
const user = require("./user")
const goods = require("./goods")

//把这些引入的中间 user接口等 存入中间件之中  路径 - 中间件
router.use("/user", user);
router.use("/goods", goods);

//引入cors中间件 实现跨域


module.exports = router;
//导出这个路由 就是把这个.js文件当做一个函数,也就是一个中间件的方式导出 在server.js文件中使用即可!
  • 原理:
  • cors.js文件 这个最好存储在一个单独的文件之中!
const allow_origin = ["localhost:9292", "www.baidu.com"]; //设置可以跨域的请求源! 但是这些都是需要开启的服务器!

function cors(req, res, next) {
  //如果可跨域的源之中 存在着这个请求的端口号 那么证明可以给与跨域
  // console.log(req.get('host'));
  if (allow_origin.includes(req.get('host'))) {

    res.set({ //设置响应头 
      "Access-Control-Allow-Origin": "*", //或者 "localhost:端口号"
      "Access-Control-Allow-Headers": "Content-Type,Content-Length, Authorization, Accept,X-Requested-With",
      "Access-Control-Allow-Methods": "PUT,POST,GET,PATCH,DELETE,OPTIONS"
    })
    // 跨域请求CORS中的预请求
    if (req.method == "OPTIONS") {
      res.sendStatus(200); /*让options请求快速返回*/
    } else {
      next();
    }
  } else {
    res.send("401")
  }
}

module.exports = cors;

jsonp

  • jsonp概念:所谓的jsonp就是包裹着json数据! 而jsonp跨域就是把json数据存放在一个回调函数里面(这个回调函数是前端自定义的函数名,随意修饰的!),用src发起http请求,来获取数据,来实现跨域!
    注意点:就是后端返回的还是一个字符串形式的数据,也就是说,在后端这边需要先处理好数据,并且返回一个回调函数,回调函数里面存放着数据!

  • 原理:就是script标签之中的src发起http请求,不受浏览器的同源策略影响!

  • 使用:

    • 0:先动态创建一个script标签,script标签之中的src用于存放着请求跨域的url
    • 1:就是在前端之中,发起一个jsonp请求,你需要传递的是一个url路径带有一个回调函数字段(url?callback=XXX回调函数名)
    • 2:而XXX回调函数名,应该为一个全局函数,则需要在外面定义一个全局函数 function XXX(data){ data => 就是这个jsonp请求回来的数据 }
创建一个服务器

需求:

  • 1:创建一个服务器
  • 2:导入所有的路由 获取到所有的路由!
  • 3:实现一个jsonp跨域!
const express = require("express"); //导入express框架 目的:用于创建一个服务器!
const router = require("router") // 导入router路由 目的:用于管理url路由的分类!

//导入一个端口号 
const {
  PORT
} = require("./port/package.json")

//导入所有的路由 => 也就是index.js这个路由
const allRouter = require("./router")
const app = express(); //创建一个服务器

app.use(allRouter); //把所有的路由,向外开放资源!
app.listen(`${ PORT }`, () => {
  console.log(`server is running ${PORT}`);
})

package.json 和 端口号中的端口配置 port文件下的 /package.json

//port文件下的 /package.json
{
  "PORT": 9292
}

//package.json => 把开启的服务为server.js 优先引入这个js文件 
// 因为这个.js文件的引入顺序限制,先查询package.json ,若是有设置main属性,就像引入,否则就引入index.js文件!
 "main": "server.js"
index.js文件的 路由的配置!

注意点:既然index.js等是路由,那么应该存放在router文件夹之中!

const express = require("express");

//创建一个路由 来管理url路径!
const router = express.Router();

//获取到user相关的接口
const user = require("./user"); //获取到user.js文件之中的router中间件

//对这些中间件url和json路径的格式化
router.use(express.json(), express.urlencoded());

//把user中的接口 存在一个中间件之中!
router.use("/user", user);

//定义一个jsonp的跨域接口 //测试这个接口是否可用 => 在浏览器之中输入 localhost:9292/jsonp 看看能不能拿到这个data数据!
router.use("/jsonp", (req, res) => {
  let {
    callback
  } = req.query; //拿到前端 发起的callback回调函数的字段 再返回前端 让前端自定义回调函数名

  const data = {
    uname: "pink",
    pwd: 1234
  }

  res.send(`${callback}(${JSON.stringify(data)})`);

})

module.exports = router;
user.js文件 => 定义着user的相关路由
const express = require("express");
const router = express.Router();

//http://localhost:9292/user 根据不同的方式 访问不同的接口!

//查
router.get("/", (req, res) => {
  console.log("get=>user");
  res.send("获取到user之中的get的数据!")
})

//增
router.post("/", (req, res) => {
  console.log("post=>user");
  //这边度需要操作数据库
  res.send("获取到user之中的post的数据!")
})

//改
router.put("/:id", (req, res) => {
  console.log("put=>user");
  let {
    id
  } = req.params
  console.log(id);
  //这边度需要操作数据库
  res.send("获取到user之中的put的数据!" + id)
})

//删
router.delete("/", (req, res) => {
  console.log("delete=>user");
  //这边度需要操作数据库
  res.send("获取到user之中的delete的数据!")
})

module.exports = router;
前端发起一个jsonp请求
  <h1>jsonp实现的跨域</h1>
  <button id="btn">点击按钮</button>

  <script>
    //定义一个全局函数,用于接收后端返回的数据 => 一个自定义的回调函数 
    function xzl(data) {
      console.log(data);
    }
    //需求:点击按钮,发起一个jsonp跨域请求
    var btn = document.querySelector("#btn");
    btn.onclick = function () {
      var script = document.createElement("script");
      script.src = 'http://localhost:9292/jsonp?callback=xzl' //向这个接口发起请求 并且传递了一个回调函数指定值! xzl为自定义回调函数名!
      document.body.appendChild(script);

      script.onload = function () { //等待script标签加载完毕后,把这个script删除!
        document.body.removeChild(script)
      }
    }
  </script>

服务器反向代理

  • 原因:就是存在接口,但是目标服务器不给权限访问,于是有了服务器反向代理!

  • 原理:就是浏览器把自己的请求委托给这边的服务器,向对应接口的服务器发起请求,得到对应接口的响应之后,被委托的服务器把这个结果返回给浏览器发起的请求! 归根结底:还是后端没有跨域的概念!

  • 安装: npm i http-proxy-milldeware

创建一个服务器
const express = require("express");
const router = require("router")
//导入一个端口号
const {
  PORT
} = require("./port/package.json")
//导入所有的路由 => 也就是index.js这个路由
const allRouter = require("./router")
const app = express(); //创建一个服务器

app.use(allRouter);
app.listen(`${ PORT }`, () => {
  console.log(`server is running ${PORT}`);
})
引入index.js中的所有路由
const express = require("express");

//创建一个路由 来管理url路径!
const router = express.Router();

const proxy = require("./proxy"); //引入proxy中间件 实现服务器反向代理

//对这些中间件url和json路径的格式化
router.use(express.json(), express.urlencoded());

router.use("/proxy", proxy); //只要请求的路径为 localhost:9292/proxy => 那么就进行服务器反向代理!

module.exports = router;
实现服务器反向代理
const express = require("express");
const router = express.Router();

//下载引入一个 实现服务器中间件 => 利用这个中间件 实现服务器反向代理!
const {
  createProxyMiddleware
} = require("http-proxy-middleware")

//这个 服务器反向代理中间件的处理程序!
const dtMiddleware = createProxyMiddleware({
  "target": "https://www.duitang.com", // 目标服务器
  "changeOrigin": true,

  //路径替换
  "pathRewrite": {
    "^/proxy/dt": "/"
  }
})
// https://www.nanshig.com/shop/index.php
const nsgMilldeware = createProxyMiddleware({
  "target": "https://www.nanshig.com/shop/index.php",
  "changeOrigin": true,

  //路径替换
  "pathRewrite": {
    "^/proxy/nsg": "/"
  }
})

router.use("/dt", dtMiddleware);
router.use("/nsg", nsgMiddleware);

module.exports = router;
在前端发起一个服务器反向代理
  <h1>跨域请求之服务器代理</h1>
  <button id="btn">获取数据</button>
  <button id="btn2">获取数据2</button>

  <script>
    const btn = document.querySelector('#btn');
    const btn2 = document.querySelector('#btn2');

    // 代理服务器接口地址1:
    // url = "https://www.duitang.com/napi/debug/setting/?app_code=mdt&app_version=6.0&1596596430304" 这是堆糖的数据接口!
    const url = 'http://localhost:9292/proxy/dt/napi/debug/setting/?app_code=mdt&app_version=6.0&1596596430304'

    //代理服务器接口地址2:
    // url = "https://www.nanshig.com/shop/index.php?act=show_store&op=ajax_flowstat_record&store_id=16&goods_id=214171&act_param=goods&op_param=index"
    const url2 =
      "http://localhost:9292/proxy/nsg?act=show_store&op=ajax_flowstat_record&store_id=16&goods_id=214171&act_param=goods&op_param=index"
    btn.onclick = () => {
      const xhr = new XMLHttpRequest();
      xhr.open('get', url, true);
      xhr.send();
    }

    btn2.onclick = () => {
      const xhr = new XMLHttpRequest();
      xhr.open('get', url, true);
      xhr.send();

      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            var data = xhr.responseText;
            console.log(data); //得到数据!
          }
        }
      }
    }
  </script>>

node爬虫技术

  • 原因:目标服务器没有接口,需要拿到数据,只有使用爬虫技术!
  • 原理:
    • 1:分析html结构,拿到响应的位置结构(经历找id的结构,还有不带重复类名)
    • 2:使用特定的工具
      • 01:request模块 => 用于发送请求,获取目标的html结构
        下载: npm i request --save-dev
        引入:const request = require("request")
      • 02:cheerio模块 => 用于过滤和获取数据(一个类似于jq的工具)
        下载:npm i cheerio --save-dev
        引入:``
    • 3:得到的数据写入数据库
    • 4:下载img到本地!

spider.js

const fs = require('fs');
const path = require('path');
const request = require('request');
const cheerio = require('cheerio');

// 1. 获取目标html结构
const url = 'http://store.lining.com/shop/goodsCate-sale,desc,1,15s15_122,15_122_m,15_122_ls15_122_10,15_122_10_m,15_122_10_l-0-0-15_122_10,15_122_10_m,15_122_10_l-0s0-0-0-min,max-0.html';
//使用request发起http请求,拿到html结构,存储在body之中
request(url, (err, res, body) => {
  //cheerio.load()方法对body结构的解析!
  let $ = cheerio.load(body);
  const goodslist = []
  //遍历每一项数据,拿到对应的数据
  $('.cate_search_content').find('.selItem').each((idx, el) => {
    const $el = $(el);
    const name = $el.find('.hgoodsName').text();
    let price = $el.find('.price').text()
    price = price.match(/[\d\.]+/)[0]
    const imgurl = $el.find('.selMainPic img').attr('orginalsrc')


    // 2. 爬取图片到本地
    // request请求图片地址,返回一个数据流
    const filename = path.basename(imgurl);
    const fileStream = fs.createWriteStream('./img/' + filename);
    request(imgurl).pipe(fileStream);

    const goods = {
      name,
      price,
      imgurl: 'img/' + filename
    }
    goodslist.push(goods);


  });
  console.log(goodslist);
})
在Vue前端项目中,如果需要访问第三方API而遇到问题,通常有几种常见的解决方案: 1. **JSONP (JSON with Padding)**: 这种方式适合于GET请求,利用script标签可以加载JSON数据。你需要在后端设置相应支持,返回一个格式如`<script>alert('success');</script>`,然后前端通过动态插入script标签解析其中的数据。 2. **CORS (Cross-Origin Resource Sharing)**: 对于现代浏览器,允许服务器设置Access-Control-Allow-Origin头来启用。在服务端设置响应头,指定允许的名或'*'通配符表示所有名。客户端的Vue应用发送Ajax请求时,会自动处理CORS。 3. **代理设置**(Proxy in Vue CLI): 使用Vue CLI构建的项目可以在配置文件`vue.config.js`中设置proxy,将所有的非同源请求转发到特定的地址,比如: ```javascript module.exports = { devServer: { proxy: { '/api': { target: 'http://third-party-api.com', // 第三方API的URL changeOrigin: true, pathRewrite: { '^/api': '' } // 如果有路径前缀,需要修改这里 } } } } ``` 4. **Nginx 或其他反向代理**:对于生产环境,可以考虑在服务器层面使用Nginx等工具做反向代理。 5. **Postman 或者 Axios 的全局拦截器**: 如果是在开发工具中遇到,也可以在Postman的预处理器或Axios的config里添加头。 注意:上述方法可能受服务器、浏览器安全策略以及API本身的限制,不是所有情况都通用。在实际操作时,建议先尝试配置后端支持,再选择合适的前端解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值