必须是下面定义对CORS安全的首部字段集合,不能是集合之外的其他首部字段。
Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width。
Content-Type的值必须是text/plain、multipart/form-data、application/x-www-form-urlencoded中任意一个值
满足上面所有的条件才不会发送预检请求,在实际项目中我们的请求格式可能是application/json格式编码,或者使用自定义请求头都会触发CORS的预检请求。
所以,在项目中是否会触发CORS的预检请求要做到心中有数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>端口号3000页面</h1>
<button>发送同源请求</button>
<button>发送跨域请求</button>
<!-- <form action="" enctype="application/x-www-form-urlencoded"></form> -->
<script>
let but = document.querySelectorAll("button")
// 同源状态下请求
but[0].onclick = function(){
let xhr = new XMLHttpRequest();
xhr.open("post","/post",true) //路径这里相对路径
xhr.onload = function(){
console.log(xhr.responseText)
}
xhr.send()
}
// 跨域请求 3000的页面请求4000的服务器
but[1].onclick = function(){
let xhr = new XMLHttpRequest();
// xhr.open("post","http://localhost:4000/post?cd=cbdata",true)
xhr.open("post","http://localhost:4000/post",true)
// post请求s设置头部 记不住可以敲form enctype 虽说默认尽量设置上
// xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded")
// // 3.与后端的3相对应 这里传json 下面的数据也得转JSON
xhr.setRequestHeader("Content-type","application/json")
xhr.setRequestHeader("test","some vlaue...")
// 5允许跨域请求携带凭证,访问的服务端也得设置,凭证是放在请求头里的,cookie是凭证之一
// 两个问题 1预检请求 2.允许前段设置头部信息
// 预检请求出现情况 1指定的请求类型options
// 2.修改了指定的属性(详情见文档)3.修改了指定的属值(详情见文档)
xhr.withCredentials = true;
xhr.onload = function(res){
console.log(xhr.responseText)
console.log(xhr.getAllResponseHeaders()) //输出设置的头部信息
}
let data = {
name:"张三"
}
xhr.send(JSON.stringify(data)) //设置响应头 后端输出{ 'name ': ' 张三' }是个对象
// 没有设置响应头 后端输出 "name = 张三"
}
function cbdata(){
console.log("good")
}
</script>
</body>
</html>
3000的服务端设置
const Koa = require("koa");
const Router = require("koa-router");
const static = require("koa-static");
let app = new Koa();
let router = new Router();
app.use(static(__dirname+"/static"));
router.get("/",ctx=>{
ctx.body ='hello';
})
router.post("/post",ctx=>{
ctx.body ='http3000';
})
// 在3000里设置cookie,在页面访问的话 会设置cookie成功,
// 点击页面发送同源请求,在浏览器Network,header中也已看到设置的cookie值
// 点击非同源按钮 没有需要去前,后端设置
router.get("/setcookie",ctx=>{
ctx.cookies.set("username","zhuangsan",{
maxAge:1000*60*60*24
});
ctx.body = "设置cookie"
})
app.use(router.routes());
app.listen(3000);
4000的服务端设置
const Koa = require("koa");
const Router = require("koa-router");
const static = require("koa-static");
const koaBody = require("koa-body")
let app = new Koa();
let router = new Router();
app.use(static(__dirname+"/static"));
app.use(koaBody())
router.get("/",ctx=>{
ctx.body ='hello';
})
// 预检请求的允许 *所有的预检请求,options处理 把post中的5项允许拉过来,js功能不需要
router.options("/*",ctx=>{
ctx.set("Access-Control-Allow-Origin","http://localhost:3000")
ctx.set("Access-Control-Expose-Headers","Content-Type,Content-Length,Date")
ctx.set("Access-Control-Expose-Methods","GET POST DELETE HEAD OPTIONS")
ctx.set("Access-Control-Allow-Headers","Content-Type,Content-Length,Authorization,test")
ctx.set("Access-Control-Allow-Credentials",true)
ctx.set("Access-Control-Max-Age",3600*24)
console.log("options")
ctx.body ='options';//随便发个数据 响应一下
})
router.post("/post",ctx=>{
// 除了手动设置允许跨域是必须设置的,其他下面几项设置都是按需设置
// 写到这一步算是请求成功,同源策略是浏览器行为与服务器无关
// 跨域请求,响应数据都能成功,浏览器但是不能显示,会报错
// 解决办法:在服务器 使用cors设置头部
// ctx.set("Access-Control-Allow-Origin","*")
// 参1:允许跨域访问 参2:允许谁 *好通配符所有网站(不安全,不能携带凭证)
// 指定访问服务器端口号
ctx.set("Access-Control-Allow-Origin","http://localhost:3000")
// 1这种方法没办法获取时间等...
// 2设置允许前段获取时间
ctx.set("Access-Control-Expose-Headers","Content-Type,Content-Length,Date")
// let cbs = ctx.query.cb;
// console.log(cbs);
// 3设置允许前段发送的请求方式 GET POST DELETE HEAD OPTIONS
ctx.set("Access-Control-Expose-Methods","GET POST DELETE HEAD OPTIONS")
// 4.允许前段设置的头部
ctx.set("Access-Control-Allow-Headers","Content-Type,Content-Length,Authorization,test")
// console.log(ctx.request.body)
// 5.允许携带凭证 true开启
ctx.set("Access-Control-Allow-Credentials",true)
// 6.设置预检请求的时间
ctx.set("Access-Control-Max-Age",3600*24)
console.log("cookie")
ctx.body ='http4000跨域';
})
app.use(router.routes());
app.listen(4000);