浏览器跨域

同源策略

同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求返回的数据接收,即请求发送了,服务器响应了,但是浏览器不接收。

同源:请求要满足协议,域名,端口都相同
http://www.test:8080/apihttp://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
posted @ 2024-05-24 01:49  冰凉小手  阅读(13)  评论(0编辑  收藏  举报