域(origins)和跨域

域(origins)是由三部分组成的标识:协议完整的主机名端口
跨域:就是非同域,同时访问另一个域的子资源。

什么是同源策略?

同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSSCSRF等攻击。同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

不会触发同源策略的标签

Tags Cross-origin Note
<iframe> 允许嵌入 取决于X-Frame-Options
<link> 允许嵌入 可能需要正确的Content-Type
<form> 允许写入 经常用此标签进行跨域写操作
<img> 允许嵌入 禁止通过JavaScript跨域读取并将其加载到canvas标签中
<audio>
<video>
允许写入
<script> 允许嵌入 可能会禁止访问特定的API

不允许被跨域访问的资源

  • 本地存储
  • indexedDB
  • Cookie
  • Ajax(XMLHttpRequest)

跨域解决方案

  • JSONP
  • 反向代理
  • CORS
  • postMessage

JSONP

jsonp原理

利用script 标签请求不会触发同源策略,动态创建script标签,和接受数据的回调函数,让后端接受到请求后,执行函数方法,塞进数据。

后端node.js jsonp支持接口

router.get("/jsonp",(req,res) =>{
   // 默认是callback的值为服务器回调函数名,也就是浏览器已经创建定义的函数,服务端会执行,并将数据放入进去
	const cb = req.query.callback ?? "cb"
	res.send(`${cb}(${JSON.stringify(db.messages)})`)
})

前端 jquery请求

$.ajax({
	url: "http:....../jsonp",
	dataType: "jsonp",
	jsonp:"callback",
	jsonpCallback:"cb",
	success(data) {
		console.log(data)
	}
})

axios 不支持jsonp
jsonp npm库
jsonp
手写实现jsonp

function jsonp(url,callback) {
	const cb ='__jp0'
	const script = document.createElement("script")
	script.src = `${url}?callback=${cb}`
	docoment.body.appendChild(script)
	window[cb] = function(data) {
		clear();
		callback(data)
	}
	function clear() {
		document.body.reamoveChild(script)
		window[cb]=null
	}
}

反向代理

  • nginx反向代理
  • nodejs库实现反向代理

CORS

CORS简介

CORS(跨域资源共享),是一种基于HTTP头的机制,该机制允许我们使用Ajax发送跨域请求,只要HTTP相应头中包含了相应的CORS相应头。
CORS需要浏览器和服务器同时支持,CORS机制在老版本的浏览器中不支持,现代浏览器都支持CORS。在使用CORS方Ajax请求时需要浏览器端代码和过去一致,服务器端需要配置CORS的响应头。

  • 简单请求
  • 复杂强求
  • 带凭证的请求(Cookie)

简单请求

不会发起CORS预检请求的请求,称为简单请求。满足下列要求的请求都是简单请求:

使用下面的请求方式

  • GET
  • POST
  • HEAD

请求头中只包含

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type

Content-Type 只能是下面三种

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

复杂请求

不满足简单请求的条件即为复杂请求,会发送两次请求,一次是预检请求OPTIONS(可缓存),后面才是真正的请求。
如:

  • 当发送请求方式为PUT/DELETE 复杂请求 =》请求方法不是简单请求中的3种
  • Content-Type值为application/json时 复杂请求 =》 Content-Type 值不满足
  • header 加token参数时 复杂请求 =》 有多余的请求头参数

axios默认发送的是Content-Type值为application/json,默认是复杂请求

使用axios发送简单请求

  1. 修改请求头为application/x-www-form-urlencoded
  2. 参数正确化
    URLSearchParams
    qs
const qs = new URLSearchParams()
qs.append("user","xxx")
qs.append("content","xxx")
qs.append("time","xxx")

axiso.post("url",qs.toString(),{
	headers: {
		token: ""
	}
})

复杂请求后端CORS配置(nodejs)

  • 手动设置请求头,实现对CORS的支持
// 设置允许的源 如果Credentials 没有开启就设置为*
res.setHeader("Access-Control-Allow-Origin","*")
// 设置允许的 复杂请求的方法
res.setHeader("Access-Control-Allow-Methods",["PUT","POST","DELETE"])
// 设置允许的 复杂请求 请求头允许的参数
res.setHeader("Access-Control-Allow-Headers",["Content-Type","token"])
// 设置允许的 复杂请求 预检请求的缓存 0为没有缓存,每次都要出现
res.setHeader("Access-Control-Max-Age",86400)
// 设置复制请求 携带cookie
res.setHeader("Access-Control-Allow-Credentials",true)
  • 利用中间件Cors 帮我们设置请求头
    详细配置看官网 cors
var cors = require('cors')
router.use(cors({
  "origin": "*",
  "methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
  "preflightContinue": false,
  "optionsSuccessStatus": 204,
  "allowedHeaders": ["Content-Type","token"],
  "credentials": true,
  "maxAge": 86500
}))
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐