网络 浏览器同源策略、跨域、解决跨域(分享)

文章目录

      • 1. 同源策略
      • 2. 跨域
      • 3. 解决跨域
        • 3.1 前端解决
        • 3.2 后端解决
        • 3.3 前后端解决

1. 同源策略

浏览器都有一个同源策略,同源策略是浏览器的一种安全策略,所谓同源是指协议、域名、端口完全相同,只有满足三者一致,才允许两个url地址之间做数据的交互

2. 跨域

当协议、域名(地址)、端口只要有一个不相同时就会跨域

3. 解决跨域

这里使用 gulp 模拟的前端服务,端口号8080,配置代码不重要主要是进行压缩,配置代码不需要看,需要注意的是,前端服务端口号8080,后端服务端口号9527就会进行跨域

注意:其实使用 vscode 就可以开启一个端口为5050的热加载,也就是说可以不使用 gulp 开启一个服务,但是在前端解决跨域需要在配置文件里代理,所以就把配置文件一起发出来了(gulp 配置文件里都有注释)

// src:入口文件
// dest:出口文件
// series:组合任务
// parallel:并行任务
// watch:观察文件变化
const { src, dest, series, parallel, watch } = require("gulp")

// 删除文件
const del = require("del")

// html代码压缩
const htmlmin = require("gulp-htmlmin")


// css处理
// less转css
const less = require("gulp-less")
// sass转css
const sass = require("gulp-sass")(require("sass"))
// css压缩
const csso = require("gulp-csso")

// js处理
// js代码压缩
const uglify = require("gulp-uglify")
// ES6转换
const babel = require("gulp-babel")

// 热更新
const connect = require("gulp-connect")

// 处理 HTML 模板
const fileinclude = require('gulp-file-include');

// 代理
const { createProxyMiddleware } = require('http-proxy-middleware')

// html 文件处理
function html() {
  // 入口文件路径
  // .pipe 输送给下一个任务
  return src("./src/*.html")
    // html模板处理
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    // html 压缩
    .pipe(htmlmin({ collapseWhitespace: true }))
    // 出口文件路径
    .pipe(dest("./dist"))
    //每次改变代码自动更新
    .pipe(connect.reload())
}

// css 文件处理
function css() {
  return src(["./src/css/*.less", "./src/css/*.scss", "./src/css/*.css"])
    // less转css
    .pipe(less())
    // sass转css
    .pipe(sass().on("error", sass.logError))
    // css压缩
    .pipe(csso())
    .pipe(dest("./dist/css"))
    .pipe(connect.reload())
}

// js 文件处理
function js() {
  return src("./src/js/*.js")
    // ES6转换
    .pipe(babel({
      presets: ["@babel/env"]
    }))
    // 进行压缩
    .pipe(uglify())
    .pipe((dest("./dist/js")))
    .pipe(connect.reload())
}

// img 文件处理
function img() {
  return src("./src/img/**")
    .pipe(dest("./dist/img"))
    .pipe(connect.reload())
}

// 清空dist下的所有文件
function clear() {
  return del(["./dist/**"]).then(() => {
    console.log("文件已清空");
  }).catch(() => {
    console.log("文件清空失败");
  })
}

// 热加载
function server() {
  connect.server({
    name: "dev",
    // 地址
    host: "localhost",
    // 端口
    port: "8080",
    // 观察哪个文件
    root: "./dist",
    // 热更新
    livereload: true
  })
}

// 观察文件变化
function watchList() {
  watch("./src/*.html", series(html))
  watch("./src/css/*.css", series(css))
  watch("./src/css/*.less", series(css))
  watch("./src/css/*.scss", series(css))
  watch("./src/js/*.js", series(js))
  watch("./src/img/**", series(img))
}

function init() {
  return [html, css, js, img]
}

// 打包
exports.build = parallel(clear, series(...init()))

// server
exports.server = series(clear, series(...init()), parallel(server, watchList))

这里使用 node 模拟的服务器(后端服务),端口号9527

// 使用 express 框架
const express = require("express")

const app = express()

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.get("/login", (request, response) => {
  response.send()
})

app.post("/login", (request, response) => {
  response.send()
})

app.listen("9527", () => {
  console.log("服务已开启: http://127.0.0.1:9527");
})
3.1 前端解决
  • 配置前端服务器代理,转发到后端服务器
    // gulp 配置文件
    // 进行代理
    const apiProxy = createProxyMiddleware("/api", { // 在配置文件中,监听的是前端的地址
      // 通过代理转发,到后端获取数据,在传给前端
      target: 'http://127.0.0.1:9527', // 目标地址
      changeOrigin: true, // 需要进行代理
      pathRewrite: { // 重写路径
        '^/api': '',
      }
    })
    
    // 热加载
    function server() {
      connect.server({
        name: "dev",
        // 地址
        host: "localhost",
        // 端口
        port: "8080",
        // 观察哪个文件
        root: "./dist",
        // 热更新
        livereload: true,
        middleware() {
          return [apiProxy]
        }
      })
    }
    
    // 前端请求部分,这一点要注意,要请求前端的地址,然后路径中间拼 api
    // html结构是使用下面 jsonp 的
    // 前端地址
    const baseUrl = "http://localhost:8080"
    
    let username;
      
    let password;
      
    document.querySelector("button").addEventListener("click", function () {
      username = document.querySelector("#username").value
      password = document.querySelector("#password").value
      
      fetch(baseUrl + "/api/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ username, password })
      }).then(res => {
        return res.json()
      }).then(data => {
        console.log("data:", data);
      }).catch(err => {
        console.log("err:", err);
      })
    })
    
3.2 后端解决
  • 配置响应头允许跨域
    // 后端服务部分
    // 服务端解决跨域 cors,这种不太安全
    app.all('*', (req, res, next) => {
      res.header("Access-Control-Allow-Origin", "*"); // 允许任何地址跨域
      res.header("Access-Control-Allow-Headers", "*"); // 允许任何请求数据格式通过
      next();
    });
    

    注意:这个时候要注意,直接访问后端服务的地址就可以了

    3.3 前后端解决
  • jsonp,利用 script 标签处理
    
    <label for="username">
      账号:
    label>
    <input type="text" id="username">
    
    <label for="password">
      密码:
    label>
    <input type="password" id="password">
    
    <button>登录button>
    
    // js部分
    // 服务端地址
    const baseUrl = "http://127.0.0.1:9527"
    let username;
    let password;
    
    // 后端传过来数据时,会执行这个函数,可以在这个函数中处理数据
    function login(params) {
      console.log(params);
    }
    document.querySelector("button").addEventListener("click", function () {
      username = document.querySelector("#username").value
      password = document.querySelector("#password").value
      
      // 点击时动态添加 script 标签,首先 script标签 为 GET 请求,而且不受跨域影响
      // 所以用 script 标签代替我们发送 get 请求
      let script = document.createElement("script")
      script.src = baseUrl + `/login?username=${username}&password=${password}`
      document.body.appendChild(script)
    })
    
    // nodejs 部分
    app.get("/login", (request, response) => {
      // 后端响应一个 login({key:value})的代码,它会执行这个代码就会找前端中的 login 函数
      // 这样就可以前后端一起解决跨域了
      response.send(`login(${JSON.stringify(request.query)})`)
    })
    

你可能感兴趣的:(网络,javascript,开发语言,ecmascript)