浏览器跨域
同源策略
同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求返回的数据接收,即请求发送了,服务器响应了,但是浏览器不接收。
同源:请求要满足协议,域名,端口都相同
http://www.test:8080/api 和 http://www.test:8080/test 同源
JSONP
同源策略针对的AJAX请求,对script,img标签没有该限制。JSONP基于此,让服务器返回一段js代码。该段代码是一个约定好的函数的执行,数据通过参数传递。
浏览器代码:
<!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> </body> <script> function callback(data) { console.log(data) } function jsonp(url) { const script = document.createElement('script') script.src = url document.body.appendChild(script) script.addEventListener('load', () => { script.remove() }) } const url = 'http://localhost:5008/getData' jsonp(url) </script> </html>
服务器代码
const express = require('express') const app = express() const port = 5008 const router = express.Router() router.get('/getData', (req, res) => { const data = { name: '小明', age: '18' } const script = `callback(${JSON.stringify(data)})` res.header('content-type', 'application/javascript').send(script) }) app.use(router) app.listen(port, () => { console.log(`server listen to ${port}`) })
缺陷
- 会影响服务器的正常响应格式:JSONP要求服务器返回一段js代码,在非跨域时又是正常的JSON格式
- 只能使用GET请求:script是GET请求
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> <script> const getCookie = 'http://localhost:5010/getCookie' const url = 'http://localhost:5010/getData' fetch(getCookie).then(() => { fetch(url, { method: 'get', headers: { a: 1 }, credentials: "include" }) }) </script> </body> </html>
服务器代码
const express = require('express') const cookieParser = require('cookie-parser') const CORSModule = require('./cors') const router = require('./router') // const cors = require('cors') const app = express() const post = 5010 app.use(cookieParser) // const allowOrigins = ['http://127.0.0.1:5500'] // app.use(cors({ // origin: (origin, callback) => { // if (!allowOrigins.includes(origin)) { // callback(new Error('not allowed')) // } // callback(null, true) // }, // methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', // credentials: true // })) app.use(CORSModule) app.use(router) app.listen(post, () => { console.log(`server listen to ${post}`) })
const allowOrigins = ['http://127.0.0.1:5500'] module.exports = (req, res, next) => { const origin = req.headers.origin if (!origin || !allowOrigins.includes(origin)) { next() return } // 预检请求 if (req.method === 'OPTIONS') { res.header('access-control-allow-methods', req.headers['access-control-request-method']) res.header('access-control-allow-headers', req.headers['access-control-request-headers']) // if (maxAge) res.header('access-control-max-age', maxAge) } // 附带身份凭证的请求 res.header('access-control-allow-credentials', true) // 简单请求 res.header('access-control-allow-origin', origin) next() }
const express = require('express') const router = express.Router() router.get('/getCookie', (req, res) => { const value = 123456 res.cookie('token', value, { path: '/', domain: 'localhost', maxAge: 7 * 24 * 3600 * 1000, //毫秒数 }) res.header("authorization", value).send() }) router.get('/getData', (req, res) => { console.log(222) const data = JSON.stringify({ name: '小明' }) res.send(data) }) module.exports = router
补充
在跨域访问时,JS只能拿到一些最基本的响应头,如:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。Access-Control-Expose-Headers
头让服务器把允许浏览器访问的头放入白名单,例如:
Access-Control-Expose-Headers: authorization, a, b
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2022-05-24 js防抖节流