一、什么是 Web 网站
Web 网站(World Wide Web)是一种通过互联网访问的信息资源集合。它由多个网页(Web Page)组成,这些网页通过超链接(Hyperlink)相互连接。用户可以使用浏览器(如 Chrome、Firefox、Safari 等)访问网站,浏览器会向服务器请求网页内容,并将其呈现给用户。
例如,像百度(百度一下,你就知道)这样的搜索引擎网站,它包含了首页、搜索结果页、新闻页等众多网页,用户通过在浏览器中输入网址或者通过搜索引擎的链接跳转来访问这些网页。
二、Web 网站的基本组成部分
(一)网页内容(HTML)
HTML(超文本标记语言 - HyperText Markup Language)是构建网页的基础。它使用标签(Tags)来描述网页的结构和内容。例如,
<html>
标签表示整个 HTML 文档的开始,
<body>
标签包含了网页中显示给用户的主要内容,如文本、图像、链接等。
代码示例:
<html>
<head>
<title>我的第一个网页</title>
</head>
<body>
<h1>欢迎来到我的网站</h1>
<p>这是一段简单的网页内容。</p>
</body>
</html>
在这个例子中,
<title>
标签中的内容会显示在浏览器的标题栏,
<h1>
标签定义了一个一级标题,
<p>
标签定义了一个段落。
(二)样式(CSS)
CSS(层叠样式表 - Cascading Style Sheets)用于控制网页的外观,如字体、颜色、布局等。它可以使网页更加美观和易于阅读。
例如,我们可以使用 CSS 来设置前面 HTML 示例中标题的颜色为蓝色,段落的字体大小为 16px。CSS 代码可以放在 HTML 文件的
<style>
标签内(内部样式表),也可以放在一个独立的.css 文件中(外部样式表),然后通过 HTML 文件中的
<link>
标签引用。
内部样式表示例:
<html>
<head>
<title>我的第一个网页</title>
<style>
h1 {
color: blue;
}
p {
font - size: 16px;
}
</style>
</head>
<body>
<h1>欢迎来到我的网站</h1>
<p>这是一段简单的网页内容。</p>
</body>
</html>
(三)脚本(JavaScript)
JavaScript 是一种编程语言,用于为网页添加交互功能。例如,可以实现表单验证(当用户提交表单时检查输入是否正确)、动画效果、响应鼠标和键盘事件等。
例如,以下 JavaScript 代码可以在用户点击按钮时弹出一个消息框:
<html>
<body>
<button onclick="alert('你点击了按钮!')">点击我</button>
</body>
</html>
三、Web 服务器
(一)作用
Web 服务器是存储和处理网页的计算机程序或硬件设备。它接收来自浏览器的请求,查找并返回相应的网页内容。例如,当用户在浏览器中输入一个网站的网址时,浏览器会向该网站对应的 Web 服务器发送请求,服务器找到请求的网页文件后,将其发送回浏览器。
(二)常见的 Web 服务器软件
**·** **Apache**:这是一款开源的、广泛使用的 Web 服务器软件。它具有高度的可定制性和稳定性,支持多种操作系统,如 Linux、Windows 等。
** · Nginx**:以高性能、低资源消耗而闻名,特别适合处理高并发的请求。它也可以作为反向代理服务器,用于提高网站的安全性和性能。
四、域名系统(DNS)
(一)作用
DNS 的主要功能是将人类容易记忆的域名(如www.baidu.com)转换为计算机能够理解的 IP 地址(如 14.215.177.38)。当用户在浏览器中输入域名时,浏览器会先向 DNS 服务器查询对应的 IP 地址,然后使用这个 IP 地址与 Web 服务器进行通信。
二)工作过程
例如,当用户访问一个新的网站时,浏览器会检查本地缓存中是否有该域名对应的 IP 地址。如果没有,它会向本地 DNS 服务器(通常由互联网服务提供商提供)发送查询请求。本地 DNS 服务器会在自己的缓存中查找,如果找不到,会向上一级 DNS 服务器查询,直到找到对应的 IP 地址或者查询失败。
五、网页布局技术
(一)表格布局(Table - based Layout)
早期的网页布局方式,通过 HTML 的
<table>
标签来组织内容。可以将网页划分为不同的单元格,把文本、图像等元素放置在这些单元格中。
例如,创建一个简单的网页布局,用表格划分页面为头部、主体和底部。
<html>
<body>
<table width="100%">
<tr>
<td colspan="2">头部区域</td>
</tr>
<tr>
<td width="30%">侧边栏</td>
<td width="70%">主体内容</td>
</tr>
<tr>
<td colspan="2">底部区域</td>
</tr>
</table>
</body>
</html>
缺点是代码结构复杂,不利于维护,并且对于屏幕阅读器等辅助设备不太友好。
(二)浮动布局(Float Layout)
利用 CSS 的
float
属性,可以让元素向左或向右浮动。通常用于创建多列布局,如将一个图像浮动到文本旁边,或者创建一个简单的两列或三列网页布局。
示例:创建一个两列布局,一列用于导航,一列用于内容。
<html>
<head>
<style>
.nav {
float: left;
width: 20%;
}
.content {
float: left;
width: 80%;
}
</style>
</head>
<body>
<div class="nav">
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">产品</a></li>
<li><a href="#">联系我们</a></li>
</ul>
</div>
<div class="content">
<h1>欢迎来到我们的网站</h1>
<p>这是主体内容部分。</p>
</div>
</body>
</html>
但是,浮动布局可能会导致一些布局问题,如父元素高度塌陷,需要使用一些清除浮动的技巧来解决。
(三)弹性布局(Flexbox)
Flexbox 是一种现代的 CSS 布局模型,用于在容器中方便地对齐和分布元素。通过设置容器的**
display: flex;
**属性,可以轻松地实现水平或垂直方向的布局。
例如,创建一个水平居中的导航栏。
<html>
<head>
<style>
.nav {
display: flex;
justify - content: center;
}
.nav ul {
list - style: none;
margin: 0;
padding: 0;
}
.nav li {
margin: 0 10px;
}
</style>
</head>
<body>
<div class="nav">
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">产品</a></li>
<li><a href="#">联系我们</a></li>
</ul>
</div>
</body>
</html>
Flexbox 提供了更灵活和强大的布局控制,能够很好地适应不同的屏幕尺寸。
(四)网格布局(Grid Layout)
CSS Grid 是一种用于创建二维布局的强大工具。可以将网页划分为行和列的网格,然后将元素放置在特定的网格单元格中。
例如,创建一个简单的网格布局,将页面划分为一个标题行、一个内容区域和一个底部行。
<html>
<head>
<style>
.container {
display: grid;
grid - template - rows: auto 1fr auto;
grid - template - columns: 1fr;
height: 100vh;
}
.header {
grid - row: 1;
background - color: lightblue;
}
.content {
grid - row: 2;
background - color: lightgreen;
}
.footer {
grid - row: 3;
background - color: lightgray;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>网站标题</h1>
</div>
<div class="content">
<p>这是网站的主要内容。</p>
</div>
<div class="footer">
<p>版权信息等</p>
</div>
</div>
</body>
</html>
六、网页性能优化
(一)文件压缩与合并
对于 CSS 和 JavaScript 文件,可以通过压缩工具(如 **UglifyJS** 对于 **JavaScript**、**CSSNano** 对于 CSS)来减小文件大小。同时,将多个小文件合并为一个大文件可以减少浏览器请求的次数。
例如,一个网站有多个 CSS 文件,如**
styles1.css
、
styles2.css
和
styles3.css
,可以使用构建工具(如 Webpack)将它们合并为一个
styles.css
**文件,并进行压缩,这样浏览器只需要请求和下载一个较小的 CSS 文件,从而加快页面加载速度。
(二)图片优化
选择合适的图片格式,如 JPEG 用于照片等色彩丰富的图像,PNG 用于需要透明背景的图像,SVG 用于矢量图形。并且可以通过工具对图片进行压缩,在保证一定质量的前提下减小文件大小。
例如,使用在线图片压缩工具 TinyPNG,它可以在不损失太多视觉质量的情况下,将 PNG 图片的文件大小减小很多。
以使用 TinyPNG API 通过 Node.js 脚本压缩图片为例,需先申请 TinyPNG API Key
首先安装依赖:
npm install tinify
** 以下是一个简单的 Node.js 脚本示例,用于压缩指定文件夹下的 PNG 图片:**
const tinify = require("tinify");
const fs = require("fs");
const path = require("path");
// 填写你的TinyPNG API Key
tinify.key = "YOUR_API_KEY";
// 图片所在文件夹路径
const imageFolder = path.join(__dirname, "images");
// 读取文件夹下所有PNG文件
fs.readdir(imageFolder, (err, files) => {
if (err) {
console.error("读取文件夹出错:", err);
return;
}
const pngFiles = files.filter(file => file.endsWith('.png'));
pngFiles.forEach(file => {
const inputPath = path.join(imageFolder, file);
const outputPath = path.join(imageFolder, `compressed_${file}`);
// 从文件读取图像数据
fs.readFile(inputPath, (err, sourceData) => {
if (err) {
console.error("读取图片文件出错:", err);
return;
}
try {
// 使用TinyPNG压缩
tinify.fromBuffer(sourceData).toFile(outputPath, (err) => {
if (err) {
console.error("压缩图片出错:", err);
return;
}
console.log(`${file} 图片压缩成功`);
});
} catch (e) {
console.error("压缩过程出现异常:", e);
}
});
});
});
运行上述脚本(使用**
node your_script_name.js
** 命令,将 **
your_script_name.js
** 替换为实际脚本文件名),就能将指定文件夹下的 PNG 图片进行压缩,并保存为带**
compressed_
** 前缀的新文件名。
(三)缓存策略
合理设置浏览器缓存可以避免用户每次访问网站都重新下载相同的资源。可以通过设置 HTTP 头信息来控制缓存时间。
例如,对于不经常变化的 CSS 和 JavaScript 文件,可以设置较长的缓存时间,如一个月(通过设置**
Cache - Control: max - age = 2592000
**),这样用户在下次访问网站时,浏览器可以直接从缓存中读取这些文件,而不需要再次从服务器下载。
在 Node.js 服务器端设置 HTTP 头信息示例,使用 Express 框架
先安装 Express:
npm install express
以下是一个简单的 Express 服务器示例,设置了对静态文件(如 CSS、JavaScript 等)的缓存策略:
const express = require('express');
const path = require('path');
const app = express();
// 设置静态文件中间件,指向public文件夹(假设静态文件都放在这里)
app.use(express.static(path.join(__dirname, 'public')));
// 对特定路由的响应设置缓存头信息示例(比如对所有.js文件)
app.get('*.js', (req, res) => {
res.set({
'Cache-Control': 'max-age=2592000', // 缓存一个月(单位:秒)
'Last-Modified': new Date().toUTCString(),
'ETag': 'your-unique-etag-value-here' // 可根据文件内容等生成唯一标识
});
res.sendFile(path.join(__dirname, 'public', req.path));
});
// 启动服务器,监听端口3000
app.listen(3000, () => {
console.log('服务器已启动,监听端口3000');
});
(四)懒加载(Lazy Loading)和预加载(Pre - loading)
懒加载是指延迟加载页面中某些元素(如图片、视频等),直到它们进入浏览器的可视区域。这样可以避免一次性加载大量资源,提高页面的初始加载速度。
预加载则是提前加载可能会用到的资源,如当用户在浏览一个页面时,可以预加载下一个页面可能用到的 CSS、JavaScript 或者图片等资源,以提高用户体验。
例如,对于一个包含很多图片的长网页,可以使用 JavaScript 实现图片懒加载。当图片滚动到可视区域时,通过修改
src
属性来加载图片。
以图片懒加载为例,使用 JavaScript 实现,结合 HTML 结构
HTML 结构示例,假设有一个包含多张图片的页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图片懒加载示例</title>
<style>
.image-container {
width: 300px;
height: 300px;
margin-bottom: 20px;
border: 1px solid gray;
}
</style>
</head>
<body>
<div class="image-container" data-src="image1.jpg"></div>
<div class="image-container" data-src="image2.jpg"></div>
<div class="image-container" data-src="image3.jpg"></div>
<script src="lazyload.js"></script>
</body>
</html>
**对应的 JavaScript 代码(
lazyload.js
文件内容)实现图片懒加载逻辑:**
function lazyLoad() {
const images = document.querySelectorAll('div.image-container');
const windowHeight = window.innerHeight;
const scrollY = window.scrollY || window.pageYOffset;
images.forEach(image => {
const imageTop = image.getBoundingClientRect().top + scrollY;
const imageBottom = imageTop + image.offsetHeight;
if (imageTop < windowHeight + scrollY && imageBottom > scrollY) {
const src = image.dataset.src;
image.style.backgroundImage = `url(${src})`;
}
});
}
// 首次加载页面时检查图片是否需要加载
lazyLoad();
// 监听滚动事件,当滚动时继续检查图片是否进入可视区域
window.addEventListener('scroll', lazyLoad);
上述 JavaScript 代码首先定义了
lazyLoad
函数,它获取页面中所有带有
data-src
属性(用来存放真实图片地址)的图片容器元素,然后判断它们是否进入浏览器可视区域,如果进入了,就将背景图片设置为对应的真实图片地址,实现懒加载效果。同时在页面加载和滚动时都调用这个函数来实时处理图片加载情况。
七、Web 安全基础
(一)跨站脚本攻击(XSS - Cross - Site Scripting)
XSS 是一种常见的安全漏洞,攻击者通过在目标网站中注入恶意脚本(通常是 JavaScript)来窃取用户信息或者执行其他恶意操作。
例如,一个网站允许用户在评论区输入内容,如果没有对用户输入进行正确的过滤和转义,攻击者可以输入一段 JavaScript 代码,如**
<script>alert('恶意脚本')</script>
**,当其他用户访问包含这个评论的页面时,浏览器就会执行这个恶意脚本。为了防止 XSS 攻击,网站开发者需要对用户输入进行严格的过滤和转义,如使用 HTML 编码来处理用户输入的文本。
**XSS - Cross - Site Scripting)防范(在 Node.js 服务器端对用户输入进行 HTML 编码过滤示例,使用
he
库 **
npm install he
** 以下是一个简单的 Express 服务器示例,接收用户在表单中输入的评论内容,并在展示到页面之前进行 HTML 编码过滤,防止 XSS 攻击:**
const express = require('express');
const he = require('he');
const app = express();
const bodyParser = require('body-parser');
// 解析表单数据
app.use(bodyParser.urlencoded({ extended: false }));
app.get('/', (req, res) => {
res.send(`
<form action="/submit-comment" method="post">
<input type="text" name="comment" placeholder="请输入评论">
<input type="submit" value="提交评论">
</form>
`);
});
app.post('/submit-comment', (req, res) => {
const userComment = req.body.comment;
const encodedComment = he.encode(userComment);
res.send(`
<h2>你提交的评论如下:</h2>
<p>${encodedComment}</p>
`);
});
app.listen(3000, () => {
console.log('服务器已启动,监听端口3000');
});
在上述代码中,当用户提交评论后,服务器端使用
he.encode
函数对用户输入的
comment
内容进行 HTML 编码,将特殊字符(如
<
、
>
等可能用于构造脚本的字符)转换为对应的 HTML 实体编码形式,然后再将编码后的内容展示到页面上,这样即使攻击者输入恶意脚本代码,也会被当作普通文本显示,而不会被浏览器执行。
(二)跨站请求伪造(CSRF - Cross - Site Request Forgery)
CSRF 攻击是指攻击者诱导用户在已登录的网站上执行非用户本意的操作。例如,攻击者构造一个恶意网站,该网站包含一个隐藏的表单,表单的目标是用户已经登录的银行网站的转账页面,当用户访问这个恶意网站时,浏览器会自动提交表单,导致用户在不知情的情况下进行转账操作。
为了防止 CSRF 攻击,网站可以采用一些防范措施,如使用 CSRF 令牌(Token)。在用户登录后,网站为用户生成一个唯一的令牌,在执行重要操作(如转账、修改密码等)时,要求用户提交这个令牌,这样攻击者在没有获取到令牌的情况下就无法成功进行 CSRF 攻击。
** CSRF - Cross - Site Request Forgery)防范(使用 CSRF 令牌示例,基于 Express 和
csurf
中间件**
npm install csurf
** 以下是一个简单的 Express 服务器示例,演示如何使用 CSRF 令牌来防范 CSRF 攻击,包含登录、执行重要操作(比如修改密码)等相关路由:**
const express = require('express');
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const app = express();
// 解析Cookie,用于存储CSRF令牌
app.use(cookieParser());
// 解析表单数据
app.use(bodyParser.urlencoded({ extended: false }));
// 创建CSRF中间件实例
const csrfProtection = csrf({
cookie: true
});
// 在登录页面设置CSRF令牌,并展示表单
app.get('/login', csrfProtection, (req, res) => {
res.cookie('XSRF-TOKEN', req.csrfToken());
res.send(`
<form action="/login" method="post">
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<input type="hidden" name="csrf_token" value="${req.csrfToken()}">
<input type="submit" value="登录">
</form>
`);
});
// 处理登录请求(这里只是简单示意,实际应用会有更多验证逻辑)
app.post('/login', csrfProtection, (req, res) => {
const { username, password } = req.body;
// 验证用户名和密码等逻辑,假设登录成功
res.send('登录成功');
});
// 需要CSRF令牌保护的修改密码路由
app.get('/change-password', csrfProtection, (req, res) => {
res.send(`
<form action="/change-password" method="post">
<input type="password" name="new-password" placeholder="新密码">
<input type="hidden" name="csrf_token" value="${req.csrfToken()}">
<input type="submit" value="修改密码">
</form>
`);
});
// 处理修改密码请求
app.post('/change-password', csrfProtection, (req, res) => {
const newPassword = req.body['new-password'];
// 执行修改密码的数据库操作等逻辑,这里简单示意
res.send('密码修改成功');
});
app.listen(3000, () => {
console.log('服务器已启动,监听端口3000');
});
在上述代码中:
**·**首先通过
csrf
中间件配置(设置
cookie: true
表示将 CSRF 令牌存储在 Cookie 中方便传递)创建了
csrfProtection
中间件实例。
** · **在登录页面(
/login
路由)和需要保护的修改密码页面(
/change-password
路由),通过
csrfProtection
中间件在响应中设置
XSRF-TOKEN
Cookie,并在表单中添加隐藏的
csrf_token
字段,其值为当前请求生成的 CSRF 令牌。
** ·**当用户提交表单(如登录、修改密码)时,
csrfProtection
中间件会验证请求中的
csrf_token
是否与 Cookie 中的
XSRF-TOKEN
匹配,如果不匹配则拒绝请求,从而防止 CSRF 攻击。
(三)SQL 注入(SQL Injection)
如果网站的后端数据库没有正确处理用户输入的查询语句,攻击者可以通过注入 SQL 代码来获取数据库中的敏感信息或者修改数据库内容。
例如,一个登录页面的 SQL 查询语句可能是**
SELECT * FROM users WHERE username = '$input_username' AND password = '$input_password'
,**如果攻击者在用户名输入框中输入
' **or 1 = 1 --**
,那么 SQL 查询语句就会变成**
SELECT * FROM users WHERE username = '' or 1 = 1 --' AND password = '$input_password'
**,这样攻击者就可以绕过密码验证登录系统。为了防止 SQL 注入,应该使用参数化查询或者存储过程来处理用户输入。
**SQL Injection)防范(以 Node.js 使用
mysql2
库进行参数化查询为例**
先安装
mysql2
库:
npm install mysql2
以下是一个简单的示例,展示如何通过参数化查询来防止 SQL 注入,实现用户登录验证功能(假设连接到一个 MySQL 数据库):
const mysql = require('mysql2/promise');
// 数据库连接配置
const connectionConfig = {
host: 'your_host',
user: 'your_user',
password: 'your_password',
database: 'your_database'
};
async function login(username, password) {
const connection = await mysql.createConnection(connectionConfig);
try {
const query = 'SELECT * FROM users WHERE username =? AND password =?';
const [rows] = await connection.execute(query, [username, password]);
if (rows.length > 0) {
console.log('登录成功');
return true;
} else {
console.log('用户名或密码错误');
return false;
}
} catch (error) {
console.error('数据库查询出错:', error);
return false;
} finally {
await connection.end();
}
}
// 模拟用户登录请求
const inputUsername = "test_user";
const inputPassword = "test_password";
login(inputUsername, inputPassword).catch(err => console.error(err));
在上述代码中,使用
mysql2
库进行数据库操作,在执行查询语句时,通过使用参数化查询(将用户名和密码作为参数传递给
execute
函数,而不是直接拼接在 SQL 语句字符串中),这样即使攻击者在输入的用户名或密码中包含恶意的 SQL 代码,数据库也会将其当作普通的参数值处理,而不会执行这些恶意代码,有效防止了 SQL 注入攻击。
请注意,以上代码示例都是简化后的示意代码,在实际的生产环境应用中,可能需要根据具体情况进行更多的配置、优化和错误处理等操作,以确保功能的完整性和安全性。
版权归原作者 grfhj 所有, 如有侵权,请联系我们删除。