news 2026/7/13 22:19:34

【自用】前端通信(渲染页面方式SSR、url参数、window.location、跨域、透传、http请求异步、缓存cookie、web安全)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【自用】前端通信(渲染页面方式SSR、url参数、window.location、跨域、透传、http请求异步、缓存cookie、web安全)

目录

请求头,响应头

HTTP版本、状态码

web安全

浏览器缓存、本地存储

渲染页面方式SSR、SEO搜索引擎优化

浏览器http请求

同步 js标签跨域、url

异步

web-worker(创建分线程):适用于计算密集型任务

index.js为加载到html页面中的主线程(js文件)

work.js为在index中创建的分线程

异步ajax、websock协议

ajax是异步的技术术语,最早的api是xhr(XMLHttpRequest)

axios

同构:同样的代码在nodejs端,浏览器端都可用

在浏览器用xhr,Node.js中使用Node的内置http模块

fetch es6 api(基于promise)

宏任务,微任务,事件循环event loop

url:?(分割url和参数) &(参数分隔符 )#(锚点,id)

&:参数顺序/无效参数不影响

urlObj.searchParams.set

多值参数

编/解码

JS编码/解码:decodeURIxxx

base64:如jZXNzL2luZGV4I

编码:Buffer.from(str).toString('base64')

解码:Buffer.from(str, 'base64').toString()

不要混用编码方法

现代浏览器自动处理部分编码

应用

浏览器的自动URL解析

保护特殊字符:illegal base64 data at input byte

404:参数丢失

window.location属性值

打开url

跨域

LocalStorage、SessionStorage、Cookie

不通过服务器:

CORS 禁用:chrome.exe --disable-web-security --user-data-dir="C:\chrome_temp"跨窗口通信 API(Window.postMessage):目标窗口监听,origin

window.addEventListener("message", receiveMessage, false);

receiveMessage(event){event.data,event.orgin,event.source.postMessage,}

jsonp:script>​​​​​,js、css,img静态资源,仅get方式,

现在浏览器兼容性高了,逐步淘汰了

代理服务器:服务器间不用同源

Nginx反向代理​​​​​​​:类似cors字段设置+proxy_pass

proxy

应用:vue.config.js

应用:本地页面跨域请求

cors(浏览器IE10以下不支持)

服务端Access-Control-Allow-Origin

preflight预检查:跨域复杂请求前,OPTIONS 请求

简单请求:GET/HEAD/POST+Content-Type:text/plain,multipart/form-data,application/x-www-form-urlencoded

报错

localhost/127.0.0.1与本机IP

应用

当服务端没有设置跨域时,可以将json伪装成text/plain

websocket:HTML5新特性,TCP,实时通信

兼容性不好,只适用于主流浏览器和IE10+

应用:webpack热更新

​​​​​​​​​​​​​​透传【开发业务】

url


请求头,响应头

HTTP版本、状态码

web安全

浏览器缓存、本地存储

渲染页面方式SSR、SEO搜索引擎优化

浏览器http请求

服务 / Server: 一直运行的程序等待被访问

同步 js标签跨域、url

img src,link href>

异步

web-worker(创建分线程):适用于计算密集型任务

当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。

web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能

Web Worker 线程无法直接访问 DOM(文档对象模型)元素、操作页面内容,也不能访问浏览器的Window和 Document 对象。这是为了防止 Web Worker影响主页面的交互

index.js为加载到html页面中的主线程(js文件)
work.js为在index中创建的分线程
index.js: 创建分线程 var w =new webwork('work.js')//创建 Web Worker 对象 向子线程发送数据 w.postmesage('数据') work.js: onmessage = function(ev) { console.log(ev);//接受主线程发送过来的ev.data数据 this.postMessage('数据')//通过 postmesage('数据') 向主线程发送数据 } 通过w.onmessage=function(ev){ev.data} ev.data 接受 a 的值. w.terminate();//终止 Web Worker

异步ajax、websock协议

ajax是异步的技术术语,最早的api是xhr(XMLHttpRequest)
axios
同构:同样的代码在nodejs端,浏览器端都可用
在浏览器用xhr,Node.js中使用Node的内置http模块
// 在浏览器中,根据其Content-Type头信息,自动转换数据 axios.get('/api/data').then(response => { // response.data 将是一个JavaScript对象 }); // 在Node.js中手动设置响应数据类型 axios.get('/api/data', { responseType: 'json' }).then(response => { // response.data 将是一个JavaScript对象 });
  • axios 新版本也支持了fetch
  • 第三方库都是基于原生API的,所以axios也还是基于xhr的
fetch es6 api(基于promise)

【JavaScript】爆肝 2 万字!一次性搞懂 Ajax、Fetch 和 Axios 的区别~

宏任务,微任务,事件循环event loop

url:?(分割url和参数) &(参数分隔符 )#(锚点,id)

http://example.com/page?param1=value1&param2=value2#section1

分隔实际的URL和参数
&URL中指定的参数间的分隔符
=左边为参数名、右边参数值
#

锚点(Anchor),用于标识文档中的特定位置或元素,

仅在客户端(前端)使用,并且由浏览器处理,不发送到服务器(后端)

指示浏览器滚动到具有id="section1"的元素处。

&:参数顺序/无效参数不影响

urlObj.searchParams.set

URL 构造函数在解析无效 URL 时会抛出异常duo

try { let urlObj = new URL(url); urlObj.searchParams.set('meishi_appid', id); // 更新或创建参数 global.viewList[id].view.webContents.loadURL(urlObj.href); } catch (error) { global.viewList[id].view.webContents.loadURL(url); } 等同于encodeURIComponent + ? const title = encodeURIComponent(res.fileName); let newUrl = `${url}?title=${title}`;

多值参数

写法示例

逗号分隔(单参数)

userNames=xxx,yyy

重复同名参数

userNames=xxx&userNames=yyy

其他分隔符,具体看接口文档

ids=1|2|3ids=1;2;3

JSON 字符串,post请求更常见

userNames=["xxx","yyy"]

编/解码

URL 规范(RFC 3986)规定,URL 只能包含以下字符:

保留字符A-Za-z0-9-_.~

特殊字符!*'();:@&=+$,/?#[]

中文等非 ASCII 字符必须经过编码(Percent-Encoding)才能使用(%xx形式)

JS编码/解码:decodeURIxxx

  • 参数值:用encodeURIComponent/URL编码/百分号编码(编码更彻底)。

如https%3A%2F%2F = https://

  • 完整 URL:用encodeURI(保留/?等结构字符)。

base64:如jZXNzL2luZGV4I

编码:Buffer.from(str).toString('base64')
解码:Buffer.from(str, 'base64').toString()

如aHR0cHM6...=bpm...

不要混用编码方法

错误的解码(如用decodeURI解码encodeURIComponent的结果)会导致乱码。

现代浏览器自动处理部分编码

在浏览器地址栏输入中文时,Chrome/Firefox 会自动编码(但代码中仍需手动处理)。

如英文逗号可以不编码。userNames=xxx,yyy

浏览器地址栏直接输入、回车,通常就能用,不用手动写成%2C

但以下情况建议编码(或必须用编码):

字符/内容原因

&=?#

有特殊含义,会破坏 URL 结构

空格

可能被转成+%20

中文、特殊符号

必须编码

用户名里本身带逗号

会和分隔符冲突,需确认接口规则

应用

浏览器的自动URL解析
// 浏览器看到这个URL会自动解析token参数,可能会重新编码 const normalUrl = res.fileUrl + '?token=' + res.token; // 成功方案:整个URL被编码,浏览器不会解析内部结构,把这个当作一个普通的编码字符串处理 const encodedUrl = encodeURIComponent(res.fileUrl + '?token=' + res.token);
保护特殊字符:illegal base64 data at input byte
// 内层编码:保护token中的特殊字符 const safeToken = encodeURIComponent(res.token); // 外层编码:保护整个URL结构 const fullEncodedUrl = encodeURIComponent(res.fileUrl + '?token=' + safeToken); // 普通URL - 浏览器会解析参数 window.open('https://example.com/file.xlsx?token=abc+def=123'); // 浏览器可能把 + 解析为空格,把 = 当作参数分隔符

404:参数丢失

SSO 跳转或后端重定向时,hash 后的参数丢失,业务页面拿不到实际参数,直接 404。

首次打开时,未登录会走 SSO 跳转链路,hash 丢失概率大。

登录后,页面可能直接渲染,不再走 SSO 跳转,所以正常。

URL 超长被截断,或参数顺序导致 hash 被提前截断。

window.location属性值

window的全局对象,表示当前页面http://www.example.com/path/index.html

window.location.href:获取/设置 url

window.location.orgin:协议、主机名和端口号部分

//https://www.example.com:8080/page.html // :// : //https%3A%2F%2Fwww.example.com%3A8080。 encodeURIComponent(window.location.origin) //encodeURIComponent用于将字符串中的特殊字符(空格、&、+、= 、?)转换为编码形式,确保URL中不包含任何无效字符 //查询参数时 或者 动态参数时 需要encodeURIComponent const url = 'https://example.com/api?param=' + encodeURIComponent(queryParam); window.location.href =`https://www.example.com/path/to/resource.html/domain=${location.host}&req=${encodeURIComponent(location.pathname)}&protocol=https${location.hash}`

window.location.protocol: 协议http

window.location.host:主机+端口(host:8080)/IP地址(127.123.32.1唯一)/域名(www.example.com助记)

window.location.hostname:主机host

window.location.port:端口8080

window.location.pathname: 资源路径path/index.html,资源index.html

window.location.hash:

window.location.search: 搜索

var searchParams = new URLSearchParams(window.location.search); console.log(searchParams.get('name')); // 输出 "John"

打开url

同源页面,自动携带所有相关Cookie到新页面,都能复用登录态。

"同基域"页面+SSO系统(携带父域Cookie),也能复用登录态。

非同源

打开方式技术原理是否继承登录态
location.href =同源导航
window.open(url)同源弹出窗口
<ahref='' target="_blank">同源新标签页
地址栏直接输入全新的浏览器实例
复制链接粘贴全新的浏览会话

跨域

跨域是浏览器内核特有的安全保护机制,命令行数据传输工具 curl不受 CORS限制

同源策略:URL 的协议、域名端口号完全一致,查询参数不影响同源,共享Cookie、LocalStorage

LocalStorage、SessionStorage、Cookie

特性LocalStorageSessionStorageCookie
数据范围同源域名同源 + 路径 + 标签页【同路径】可通过 Domain【域名】/Path【路径】 灵活配置
持久性持久,需手动或代码清除标签页关闭即清除可设置过期时间 (Expires/Max-Age)
跟随请求(自动在 HTTP 头中发送)
可访问性仅客户端 JavaScript仅客户端 JavaScript客户端和服务器均可访问

同域:通常指主域名相同 ,不关心协议和端口,不是标准术语

不通过服务器:

CORS 禁用:chrome.exe --disable-web-security --user-data-dir="C:\chrome_temp"
跨窗口通信 API(Window.postMessage):目标窗口监听,origin

window.addEventListener("message", receiveMessage, false);
receiveMessage(event){event.data,event.orgin,event.source.postMessage,}

http://localhost:3000

<!DOCTYPE html> <html> <head> <script> window.addEventListener("DOMContentLoaded", (event) => { // 获取目标窗口的引用 const targetWindow = document.getElementById("targetFrame").contentWindow; // 给按钮添加点击事件处理函数 document.getElementById("sendButton").addEventListener("click", () => { // 向目标窗口发送消息 targetWindow.postMessage("你好,来自页面1!", "http://localhost:4000"); }); }); // 接收消息的处理函数 function receiveMessage(event) { // 确保消息来自预期的源 if (event.origin !== "http://localhost:4000") { return; } console.log("接收到的消息:", event.data); } // 监听消息事件 window.addEventListener("message", receiveMessage, false); </script> </head> <body> <button id="sendButton">发送消息</button> <iframe id="targetFrame" src="http://localhost:4000"></iframe> </body> </html>

http://localhost:4000

<!DOCTYPE html> <html> <head> <script> // 监听消息事件 window.addEventListener("message", receiveMessage, false); // 接收消息的处理函数 function receiveMessage(event) { // 确保消息来自预期的源 if (event.origin !== "http://localhost:3000") { return; } console.log("接收到的消息:", event.data); // 向页面1发送回应消息 event.source.postMessage("你好,来自页面2!", event.origin); } </script> </head> <body> <h1>页面2</h1> </body> </html>

jsonp:script>​​​​​,js、css,img静态资源,仅get方式,

现在浏览器兼容性高了,逐步淘汰

JSONP(JSON WithPadding)是利用<script src=XXX>跨域

因为是动态创建script标签,所以它只支持get请求不支持post请求

代理服务器:服务器间不用同源

正向代理主要是用来解决访问限制问题;

反向代理则是提供负载均衡、安全防护等作用。

Nginx反向代理​​​​​​​:类似cors字段设置+proxy_pass

前端应用运行在http://localhost:3000,跨域访问后端 API ,它运行在http://localhost:8000

server { #HTTP 协议来监听请求,应该使用 listen 80; listen 80; server_name localhost; location /api { proxy_pass http://localhost:8000; # 允许来自前端应用的跨域请求 add_header 'Access-Control-Allow-Origin' 'http://localhost:3000'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # 支持 OPTIONS 请求,用于预检请求 if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' 'http://localhost:3000'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # 响应预检请求,直接返回 204 No Content add_header 'Content-Length' 0; add_header 'Content-Type' 'text/plain charset=UTF-8'; return 204; } } }

proxy

应用:vue.config.js
const configStatic = { proxy: { '/test': { target: 'http://www.xx.cn',// 设置目标服务器的地址 changeOrigin: true, pathRewrite: { '^/test': '/' } } } module.exports = configStatic
应用:本地页面跨域请求

浏览器有同源策略 / 跨域(CORS):

  • 页面在:http://10.253.70.42:3000
  • 接口在:https://xiaomi.77.com
  • 域名、端口、协议不同 → 浏览器可能禁止页面里的 JS 直接fetch外站接口

常见解决办法:本机起一个代理(proxy)

浏览器 → 同源:http://本机:3000/proxy?url=真实接口

本机服务 → 服务端去请求 →https://xiaomi.77.com...

本机服务 → 把结果还给浏览器

浏览器只和「本机 3000」说话,跨域由服务器完成(服务器不受浏览器 CORS 限制)。

//index.html const targetUrl = `https://xiaomi.77.com/updateGrayUser?${params}`; const url = `/proxy?url=${encodeURIComponent(targetUrl)}`; fetch(url)
  1. 托管页面:让index.html能通过http://打开(不是file://
  2. 代理转发:页面不能直接跨域访问外站时,由本机代为请求
// server.js 靠本机的 Node进程(服务端)去请求外站,绕过浏览器的跨域限制 // require 加载 Node.js 自带的能力,不用额外安装。 const http = require('http'); const https = require('https'); const fs = require('fs'); const path = require('path'); const { URL } = require('url'); const PORT = 3000; function proxy(targetUrl, res) { //由 Node 去请求外站 https.get(targetUrl, (proxyRes) => { let data = ''; proxyRes.on('data', (chunk) => { data += chunk; }); proxyRes.on('end', () => { res.writeHead(proxyRes.statusCode || 200, { 'Content-Type': proxyRes.headers['content-type'] || 'application/json; charset=utf-8', 'Access-Control-Allow-Origin': '*', }); res.end(data); }); }).on('error', (err) => { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: err.message })); }); } http.createServer((req, res) => { const url = new URL(req.url, `http://${req.headers.host}`); if (url.pathname === '/proxy') { const targetUrl = url.searchParams.get('url'); if (!targetUrl) { res.writeHead(400, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ error: 'missing url parameter' })); } return proxy(targetUrl, res); } const file = path.join(__dirname, url.pathname === '/' ? 'index.html' : url.pathname.slice(1)); if (!file.startsWith(__dirname)) { res.writeHead(403).end('Forbidden'); return; } fs.readFile(file, (err, data) => { if (err) { res.writeHead(404).end('Not Found'); return; } const type = path.extname(file) === '.html' ? 'text/html; charset=utf-8' : 'text/plain'; res.writeHead(200, { 'Content-Type': type }).end(data); }); }).listen(PORT, '0.0.0.0', () => { console.log(`http://localhost:${PORT}`); });

​​​​​​​

cors(浏览器IE10以下不支持

服务端Access-Control-Allow-Origin

preflight预检查:跨域复杂请求前,OPTIONS 请求

预检请求是指浏览器在发送跨域请求之前,会先发送一个OPTIONS 请求,用于询问服务器是否接受实际的请求。

预检请求主要用于对复杂请求(例如包含自定义请求头或使用非简单标头字段的请求)进行安全验证。

简单请求:GET/HEAD/POST+Content-Type:text/plain,multipart/form-data,application/x-www-form-urlencoded

条件2:除了被允许自定义请求头(例如:X-PINGOTHER),请求头仅包含一些简单标头字段,如:Accept、Accept-Language、Content-Language、Content-Type,Range。

其中Content-Type 的值仅限于下列三者之一:

  • text/plain无格式正文(可以有效避免XSS漏洞)
  • multipart/form-data(键值对型数据)
  • application/x-www-form-urlencoded(URLencoded)(默认

报错

localhost/127.0.0.1与本机IP


将 `localhost` 改为本机 IP 后出现 CORS 跨域无法登录,原因如下:

1. **同源策略限制**:浏览器的同源策略要求协议、域名、端口完全一致。`localhost` 和 `127.0.0.1` 或本机 IP(如 `192.168.x.x`)在浏览器看来是不同的源。


2. **Cookie 不共享**:如果你的登录态(如 session、token、cookie)是在 `localhost` 下设置的,切换到本机 IP 时,cookie 不会自动带上,导致认证失效,接口返回未登录。


3. **CORS 配置问题**:后端如果只允许 `localhost` 跨域,换成 IP 后请求来源变了,CORS 校验失败,浏览器拦截请求。

应用

当服务端没有设置跨域时,可以将json伪装成text/plain

原理:

包装成简单请求,以躲过预检查。但是有些客户端或者代理还是会预检查

安全:

浏览器对于 JSON 响应的默认处理机制是自动将其解析为 JavaScript 对象。

当浏览器接收到响应时,如果响应的 Content-Type 是application/json没有指定 Content-Type,浏览器会自动将响应体解析为JSON,JavaScript 对象,如果是恶意代码可能会被执行,导致安全漏洞或攻击。

通过将 JSON 响应伪装成 text/plain 类型,可以避免浏览器将响应自动解析为 JavaScript 对象的默认行为。

这样一来,JavaScript 代码需要手动对响应进行解析,确保数据的安全性和正确性。这种伪装可以提供额外的安全层,防止对于响应的自动解析可能带来的安全风险。

//请求头 GET /example HTTP/1.1 Host: example.com Accept: text/plain //响应头 HTTP/1.1 200 OK Content-Type: text/plain //响应体 {"foo": "bar"}

跨源资源共享(CORS) - HTTP | MDN

Cross-Origin Resource Sharing (CORS) - HTTP | MDN

websocket:HTML5新特性,TCP,实时通信

兼容性不好,只适用于主流浏览器和IE10+
应用:webpack热更新

HTML5 的一个持久化的协议,它实现了浏览器与服务器全双工通信

WebSocketHTTP都是应用层协议,都基于TCP 协议

WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了

原生WebSocket API使用起来不太方便

Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容

本地文件socket.html向localhost:3000发生数据和接受数据:

// socket.html <script> let socket = new WebSocket('ws://localhost:3000'); socket.onopen = function () { socket.send('我爱你');//向服务器发送数据 } socket.onmessage = function (e) { console.log(e.data);//接收服务器返回的数据 } </script>
// server.js let express = require('express'); let app = express(); let WebSocket = require('ws');//记得安装ws let wss = new WebSocket.Server({port:3000}); wss.on('connection',function(ws) { ws.on('message', function (data) { console.log(data); ws.send('我不爱你') }); })

​​​​​​​​​​​​​​透传【开发业务】

透传 (Transparent Transmission):数据从一个系统/模块传递到另一个系统/模块,中间不做任何处理或修改

参数是否敏感?

是 → 使用POST请求体/加密传输
否 → 参数是否简单且量小?

是 → 使用URL参数(跨域跨端)
否 → 数据是否复杂或量大?

是 → 使用状态管理/存储(Vuex、LocalStorage)
否 → 是否需要持久化?

是 → LocalStorage/SessionStorage
否 → 是否临时性通信?

是 → 事件总线/全局状态

url

// 假设当前URL:https://example.com/path?source=ehr&extra=xxx const urlParams = new URLSearchParams(window.location.search); // window.location.search = "?source=ehr&extra=xxx" // urlParams.get('source') → "ehr" ✅ //URLSearchParams 构造函数不会解析完整 URL,但是如果字符串起始位置有 ? 的话会被去除。 const paramsString1 = "http://example.com/search?query=%40"; const searchParams1 = new URLSearchParams(paramsString1); console.log(searchParams1.has("query")); // false console.log(searchParams1.has("http://example.com/search?query")); // true
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 22:16:48

5分钟快速上手:TikTok抖音视频下载完整指南

5分钟快速上手&#xff1a;TikTok抖音视频下载完整指南 【免费下载链接】TikTokDownloader TikTok 发布/喜欢/合辑/直播/视频/图集/音乐&#xff1b;抖音发布/喜欢/收藏/收藏夹/视频/图集/实况/直播/音乐/合集/评论/账号/搜索/热榜数据采集工具/下载工具 项目地址: https://g…

作者头像 李华
网站建设 2026/7/13 22:16:00

复盘SQL①

SQLtest 01-07查询所有员工的姓名、工资以及所在部门的名称。查询每个部门的员工人数和平均工资。查询工资高于公司平均工资的员工姓名、工资和部门名称&#xff08;使用子查询&#xff09;。查询每个部门中工资最高的员工的姓名、工资和部门名称&#xff08;使用子查询作为临时…

作者头像 李华
网站建设 2026/7/13 22:15:43

Python 自动化之批量重命名与智能文件分类

电脑用久了&#xff0c;桌面和下载文件夹总会变得一团糟。用 Python 写几个脚本&#xff0c;一键重命名、按类型归档、清理重复文件。 一、批量重命名 1. 统一命名规则 import osdef batch_rename(directory, prefix"file", start1, digits3):"""统一…

作者头像 李华
网站建设 2026/7/13 22:11:08

能源国企总额管控改革:北京华恒智信薪酬管理案例

【客户行业】 能源业&#xff1b;国有企业&#xff1b;集团化管控【问题类型】 工资总额预算编制&#xff1b;福利费用管理&#xff1b;分类管控机制【客户背景】某省属能源集团是华中地区能源行业的骨干企业&#xff0c;成立于国家能源体制改革初期&#xff0c;经过多年发展已…

作者头像 李华
网站建设 2026/7/13 22:10:56

通信企业战略转型人力支撑:北京华恒智信管理案例

【客户行业】通信行业【问题类型】提高人效比【客户背景】某大型通信公司是集设计、生产、运营、维护、销售于一体的综合信息服务商&#xff0c;旨在向客户提供综合的信息化解决方案和专业化的通信服务。该公司已积累了较为丰富和领先的行业经验&#xff0c;随着技术的发展&…

作者头像 李华