跨域请求
跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。
首先我们要知道为什么会有跨域问题,跨域是指,当前的网站访问了其他不同的(域、协议或端口)地址。大概意思就是被浏览器认定为不同源的两个地址不能互相访问,这保护了网页的隐私和安全。
容易产生跨域的情况:网络请求其他页面的服务,a标签download下载陌生页的内容,canvas绘图使用未知的图片源......
浏览器认定为不同源可以参考
通过nodejs解决跨域
既然在网页中跨域不好解决,那我们可以通过后端来访问(后端是没有同源策略的,这也是网络爬虫能爬取信息的原因),我们可以通过node的express服务拿到网络请求数据,在将数据传递给自己的网页(这里将express的响应设置为不限制同源访问)
let url = "https://api.tangdouz.com/a/biaoq.php";
// 这是一个表情包的api,直接访问会触发跨域
// 它有两个参数,一个是retrun 返回的数据格式,默认是text,可选json
// 一个是关键字 nr String 它会找出相关的表情包图片
直接在网页中对其发起get请求会产生跨域错误,所以我们通过nodejs拿数据
const express = require('express');
const app = express()
const port = 3000
let url = "https://api.tangdouz.com/a/biaoq.php";// 前端跨域的请求,通过后端请求解决跨域,在返回到前端
let params1 = "json";
let params2 = "笑脸"; // 默认没有参数时使用笑脸参数
let imgArr = [];// 用来存放图片信息
app.get('/img', (req, res) =>{
// 在请求中设置响应头
// 处理跨域问题
res.header("Access-Control-Allow-Origin", "*"); // 设置响应头,*表示任何地址都亦可以访问
console.log("收到一次访问,参数为:",req.query);
if(req.query){
params2 = req.query.str;
}
(async()=>{
let response = await fetch(url+`?return=${params1}&nr=${params2}`,{"method":"get"});
if(response.ok){// 访问成功对数据进行处理
let data = await response.json();
// console.log(data,response.status);
for(let i = 0;i<data.length;i++){
imgArr.push(data[i].thumbSrc);
}
}else{
console.log("访问失败!",response.status)
}
console.log(imgArr);
res.send(imgArr);// 将内容响应出去
imgArr = [];// 响应后将数组置空
})()
});
app.listen(port, () => console.log(`Example app listening on port http://127.0.0.1:${port}/img !`))
// 处理跨域问题
res.header("Access-Control-Allow-Origin", "*"); // 设置响应头,*表示任何地址都亦可以访问
// 解除同源限制
通过node启动服务
直接在网页中请求一次
、
可以看到能够拿到数据,
简单构建好node后,再写出前端页面,并以node提供的中间件进行数据访问
// index.js:
const search = document.getElementById("imgName");
const bt = document.getElementById("bt");
const imgList = document.getElementsByClassName("imgList")[0];
let url = "http://127.0.0.1:3000/img?str=";// node提供的api接口服务
let imgArr = [];
const re = new XMLHttpRequest();
bt.onclick = ()=>{
// console.log(search.value);
if(search.value){
re.open("get",url+search.value);
re.onload = ()=>{
if(re.status == 200 && re.readyState == 4){
// console.log(re.response);
if(imgArr[0]){//页面上已有图片
// 对图片进行移除
let oldImgArr = document.getElementsByTagName("img");
while(oldImgArr.length>0){
// document.body.removeChild(oldImgArr[i]);
oldImgArr[0].remove();
}
// 重新渲染新图片
imgArr =JSON.parse(re.response);
for(let i =0 ;i<imgArr.length;i++){
let img = new Image();
img.src = imgArr[i];
imgList.appendChild(img);
}
}else{
imgArr =JSON.parse(re.response);
// 渲染新图片
for(let i =0 ;i<imgArr.length;i++){
let img = new Image();
img.src = imgArr[i];
imgList.appendChild(img);
}
}
}else{
console.log("请求失败");
}
}
re.send();
}else{
alert("请输入正确的信息!");
}
}
search.onkeydown = (e)=>{
if(e.keyCode === 13){//回车键
bt.onclick();
}
// console.log(e.keyCode);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表情包搜索</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="input-container">
<input type="text" id="imgName" name="imgName" required="">
<label for="input" class="label">表情包</label>
<div class="underline"></div>
<button id = "bt" class="btn">
<span class="icon">
<svg width="19px" height="19px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path opacity="1" d="M14 5H20" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> <path opacity="1" d="M14 8H17" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M21 11.5C21 16.75 16.75 21 11.5 21C6.25 21 2 16.75 2 11.5C2 6.25 6.25 2 11.5 2" stroke="" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"></path> <path opacity="1" d="M22 22L20 20" stroke="" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>
</span>
</button>
</div>
<div class="imgList"></div>
<script src="index.js"></script>
</body>
</html>
body {
background-color: #e8f0fe;
}
.imgList{
margin: auto;
width: 90%;
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
background-color: white;
}
.imgList img{
object-fit: contain;/*保持原图的比例和大小*/
flex-shrink: 0;
margin-top: 10px;
max-width: 95%;
}
.input-container {
position: relative;
margin: 50px auto;
width: 500px;
max-width: 90%;
}
.input-container input[type="text"] {
font-size: 20px;
width: 100%;
border: none;
border-bottom: 2px solid #ccc;
padding: 5px 0;
background-color: transparent;
outline: none;
color: #70d9ff;
}
.input-container .label {
position: absolute;
top: 0;
left: 0;
color: #ccc;
transition: all 0.3s ease;
pointer-events: none;
}
.input-container input[type="text"]:focus~.label,
.input-container input[type="text"]:valid~.label {
top: -20px;
font-size: 0.8em;
color: #70d9ff;
}
.input-container .underline {
position: absolute;
bottom: 0;
left: 0;
height: 2px;
width: 100%;
background-color: #333;
transform: scaleX(0);
transition: all 0.3s ease;
background-color: #70d9ff;
}
.input-container input[type="text"]:focus~.underline,
.input-container input[type="text"]:valid~.underline {
transform: scaleX(1);
}
.btn {
position: absolute;
left: calc(100% - 40px ) ;
text-decoration: none;
display: inline-block;
width: 40px;
height: 40px;
transition: all 0.2s;
border: none;
border-radius: 50%;
color: #ccc;
background-color: transparent;
}
.btn:hover {
transform: translateY(-3px);
color: #70d9ff;
/* box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); */
}
.icon svg{
stroke: #ccc;
}
.btn:hover .icon svg{
stroke: #70d9ff;
}
.btn:active {
transform: translateY(-1px);
/* box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); */
}
.btn::after {
content: "";
display: inline-block;
height: 100%;
width: 100%;
border-radius: 100px;
position: absolute;
top: 0;
left: 0;
z-index: -1;
transition: all .4s;
}
.btn::after {
background-color: #e8f0fe;
}
.btn:hover::after {
background-color: #ffffff;
transform: scaleX(1.4) scaleY(1.6);
opacity: 0;
}
最终会有4个文件:
express.js :提供中间服务拿数据
index.html :展示页
index.js :获取express拿到的数据
style.css :提供样式
查看结果:
注意:先启动node服务,再打开网页
可以看到我们的页面成功拿到了图片
思路总结
这个方法的思路是:通过后端不受同源限制的原理拿数据,再将数据返回给自己的页面(因为是自己的后端服务,可以解开同源限制)