目录
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
引入:``
- 01:request模块 => 用于发送请求,获取目标的html结构
- 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);
})