跨域访问
- 只要协议、主机、端口之一不同,就不同源,例如
- http://localhost:7070/a 和 https://localhost:7070/b 就不同源
- 同源检查是浏览器的行为,而且只针对 fetch、xhr 请求
- 如果是其它客户端,例如 java http client,postman,它们是不做同源检查的
- 通过表单提交、浏览器直接输入 url 地址这些方式发送的请求,也不会做同源检查
- 更多相关知识请参考
- 跨源资源共享(CORS) - HTTP | MDN (mozilla.org)
请求响应头方式
- fetch 请求跨域,会携带一个 Origin 头,代表【发请求的资源源自何处】,目标通过它就能辨别是否发生跨域
- 我们的例子中:student.html 发送 fetch 请求,告诉 tomcat,我源自 localhost:7070
- 目标资源通过返回 Access-Control-Allow-Origin 头,告诉浏览器【允许哪些源使用此响应】
- 我们的例子中:tomcat 返回 fetch 响应,告诉浏览器,这个响应允许源自 localhost:7070 的资源使用
实例:
请求方:
- 我们的例子中:tomcat 返回 fetch 响应,告诉浏览器,这个响应允许源自 localhost:7070 的资源使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style scoped>
div {
font-family: 华文行楷;
font-size: 20px;
}
.title {
margin-bottom: 10px;
font-size: 30px;
color: #333;
text-align: center;
}
.row {
background-color: #fff;
display: flex;
justify-content: center;
}
.col {
border: 1px solid #f0f0f0;
width: 15%;
height: 35px;
text-align: center;
line-height: 35px;
}
.bold .col {
background-color: #f1f1f1;
}
</style>
</head>
<body>
<div>
<div class="title">学生列表</div>
<div class="thead">
<div class="row bold">
<div class="col">编号</div>
<div class="col">姓名</div>
<div class="col">性别</div>
<div class="col">年龄</div>
</div>
</div>
<div class="tbody">
</div>
</div>
<template id="tp">
<div class="row">
<div class="col">xx</div>
<div class="col">xx</div>
<div class="col">xx</div>
<div class="col">xx</div>
</div>
</template>
<script>
// **访问Tomcat地址存在跨域问题(不同源)**
fetch("http://localhost:8080/api/students")
.then(response=>response.json())
.then(students=>{
const tp=document.querySelector("#tp");
const row=tp.content;
const [r1,r2,r3,r4]=row.querySelectorAll(".col");
const tbody=document.querySelector(".tbody");
for (const {id,name,sex,age} of students){
r1.textContent=id;
r2.textContent=name;
r3.textContent=sex;
r4.textContent=age;
//复制元素
const newRow=document.importNode(row,true)
//插入节点
tbody.appendChild(newRow);
}
}).catch((e)=>{console.log(e)});
</script>
</body>
</html>
Tomcat响应方:
package com.qwy.controller;
import com.inspur.bean.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Controller
public class HelloController {
@RequestMapping("/api/students")
//解决不同源跨域访问问题
@CrossOrigin("http://localhost:7070")
@ResponseBody
public List<Users> getMessage() {
Users users1 = new Users(1, "刘备", "男", 12);
Users users2 = new Users(2, "张非", "男", 12);
Users users3 = new Users(3, "关羽", "女", 12);
Users users4 = new Users(4, "刘邦", "男", 12);
Users users5 = new Users(5, "诸葛", "女", 12);
Users users6 = new Users(6, "刘备", "男", 12);
Users users7 = new Users(7, "张非", "男", 12);
Users users8 = new Users(8, "关羽", "女", 12);
Users users9 = new Users(9, "刘邦", "男", 12);
Users users10 = new Users(10, "诸葛", "女", 12);
List<Users> usersList = new ArrayList<Users>();
Collections.addAll(usersList, users1, users2, users3, users4, users5, users6, users7, users8, users9, users10);
return usersList;
}
}
代理方式
npm install http-proxy-middleware --save-dev
在 express 服务器启动代码中加入
import {createProxyMiddleware} from 'http-proxy-middleware'
// ...
app.use('/api', createProxyMiddleware({ target: 'http://localhost:8080', changeOrigin: true }));
fetch 代码改为
const resp = await fetch('http://localhost:7070/api/students')
或
const resp = await fetch('/api/students')
实例:
前端服务器express 服务器启动代码中(main.js):
import express from 'express'
import {createProxyMiddleware} from 'http-proxy-middleware'
const app = express()
//代理实现跨域问题解决(以/api开头的地址代理访问http://localhost:8080)
app.use('/api', createProxyMiddleware({ target: 'http://localhost:8080', changeOrigin: true }))
// 添加静态资源的目录
app.use(express.static('./'))
app.listen(7070)
前端页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style scoped>
div {
font-family: 华文行楷;
font-size: 20px;
}
.title {
margin-bottom: 10px;
font-size: 30px;
color: #333;
text-align: center;
}
.row {
background-color: #fff;
display: flex;
justify-content: center;
}
.col {
border: 1px solid #f0f0f0;
width: 15%;
height: 35px;
text-align: center;
line-height: 35px;
}
.bold .col {
background-color: #f1f1f1;
}
</style>
</head>
<body>
<div>
<div class="title">学生列表</div>
<div class="thead">
<div class="row bold">
<div class="col">编号</div>
<div class="col">姓名</div>
<div class="col">性别</div>
<div class="col">年龄</div>
</div>
</div>
<div class="tbody">
</div>
</div>
<template id="tp">
<div class="row">
<div class="col">xx</div>
<div class="col">xx</div>
<div class="col">xx</div>
<div class="col">xx</div>
</div>
</template>
<script>
// 访问Tomcat地址存在跨域问题(不同源)
fetch("http://localhost:7070/api/students")
.then(response=>response.json())
.then(students=>{
const tp=document.querySelector("#tp");
const row=tp.content;
const [r1,r2,r3,r4]=row.querySelectorAll(".col");
const tbody=document.querySelector(".tbody");
for (const {id,name,sex,age} of students){
r1.textContent=id;
r2.textContent=name;
r3.textContent=sex;
r4.textContent=age;
//复制元素
const newRow=document.importNode(row,true)
//插入节点
tbody.appendChild(newRow);
}
}).catch((e)=>{console.log(e)});
</script>
</body>
</html>
后端:
package com.qwy.controller;
import com.inspur.bean.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Controller
public class HelloController {
@RequestMapping("/api/students")
//解决不同源跨域访问问题
// @CrossOrigin("http://localhost:7070")
@ResponseBody
public List<Users> getMessage() {
Users users1 = new Users(1, "刘备", "男", 12);
Users users2 = new Users(2, "张非", "男", 12);
Users users3 = new Users(3, "关羽", "女", 12);
Users users4 = new Users(4, "刘邦", "男", 12);
Users users5 = new Users(5, "诸葛", "女", 12);
Users users6 = new Users(6, "刘备", "男", 12);
Users users7 = new Users(7, "张非", "男", 12);
Users users8 = new Users(8, "关羽", "女", 12);
Users users9 = new Users(9, "刘邦", "男", 12);
Users users10 = new Users(10, "诸葛", "女", 12);
List<Users> usersList = new ArrayList<Users>();
Collections.addAll(usersList, users1, users2, users3, users4, users5, users6, users7, users8, users9, users10);
return usersList;
}
}