当前位置: 首页 > news >正文

前后端路径处理完整指南:从零开始理解Web开发中的路径问题

目录

  • 1. 前言:为什么路径问题这么重要?
  • 2. 基础概念:什么是路径?
  • 3. 前端路径详解
    • 3.1 相对路径 vs 绝对路径
    • 3.2 前端开发中的特殊路径
    • 3.3 构建工具如何处理路径
  • 4. 后端路径处理
    • 4.1 静态文件服务
    • 4.2 路由映射
    • 4.3 文件系统路径
  • 5. 前后端协调最佳实践
  • 6. 常见问题与解决方案
  • 7. 实战案例:完整项目路径配置

1. 前言:为什么路径问题这么重要?

想象一下,你在一个大型商场里,想要找到某个商店。如果商场没有明确的指示牌和路径规划,你会不会迷路?Web开发中的路径问题也是如此。

路径问题直接影响:

  • 用户能否正常访问你的网站
  • 图片、样式、脚本能否正确加载
  • 开发效率和生产环境的稳定性
  • 网站的SEO和性能

常见错误:

  • 图片显示不出来(404错误)
  • 样式文件加载失败
  • 开发环境正常,生产环境出错
  • 移动文件后链接失效

2. 基础概念:什么是路径?

2.1 路径的本质

路径就是告诉计算机"去哪里找文件"的地址。就像你家的地址一样,有了地址,邮递员才能把包裹送到正确的地方。

2.2 两种基本路径类型

2.2.1 相对路径(Relative Path)

定义: 相对于当前文件位置的路径

特点:

  • ./../ 开头,或者直接写文件名
  • 会随着文件位置的变化而变化
  • 更灵活,但容易出错

例子:

<!-- 当前文件在 /pages/about.html -->
<img src="../images/logo.png" />
<!-- 向上一级,然后找images文件夹 -->
<img src="./avatar.jpg" />
<!-- 当前目录下的avatar.jpg -->
<img src="banner.png" />
<!-- 当前目录下的banner.png -->
2.2.2 绝对路径(Absolute Path)

定义: 从网站根目录开始的完整路径

特点:

  • / 开头
  • 不会因为文件位置变化而变化
  • 更稳定,但需要服务器正确配置

例子:

<!-- 无论文件在哪里,这些路径都是一样的 -->
<img src="/images/logo.png">     <!-- 网站根目录下的images文件夹 -->
<link href="/css/style.css">    <!-- 网站根目录下的css文件夹 -->
<script src="/js/app.js">       <!-- 网站根目录下的js文件夹 -->

2.3 路径对比表

特性相对路径绝对路径
写法./file.js../folder/file.js/folder/file.js
稳定性文件移动后可能失效文件移动后仍然有效
服务器配置不需要特殊配置需要服务器路由配置
开发复杂度简单需要理解服务器配置
维护性较差较好

3. 前端路径详解

3.1 相对路径 vs 绝对路径

3.1.1 相对路径的使用场景

适合用相对路径的情况:

<!-- 1. 同一目录下的文件 -->
<script src="utils.js"></script><!-- 2. 子目录中的文件 -->
<img src="images/photo.jpg" /><!-- 3. 父目录中的文件 -->
<link href="../styles/main.css" />

相对路径的问题:

<!-- 问题示例:文件结构变化后路径失效 -->
<!-- 原始结构 -->
pages/ about.html ← 当前文件 images/ logo.png<!-- 在about.html中 -->
<img src="images/logo.png" />
<!-- ✅ 正确 --><!-- 文件移动后 -->
about/ about.html ← 文件移动了 images/ logo.png<!-- 原来的路径就错了 -->
<img src="images/logo.png" />
<!-- ❌ 错误!应该是 ../images/logo.png -->
3.1.2 绝对路径的使用场景

适合用绝对路径的情况:

<!-- 1. 公共资源(所有页面都会用到) -->
<link href="/css/common.css" />
<script src="/js/jquery.min.js"><!-- 2. 静态资源(图片、字体等) --><img src="/images/logo.png"><link href="/fonts/roboto.css"><!-- 3. API接口 --><script>fetch('/api/users')  // 绝对路径,更稳定
</script>

3.2 前端开发中的特殊路径

3.2.1 @ 符号路径(别名路径)

什么是别名路径?
别名路径是构建工具(如Webpack、Vite)提供的简化路径写法。

配置示例(webpack.config.js):

module.exports = {resolve: {alias: {'@': path.resolve(__dirname, 'src'),'@components': path.resolve(__dirname, 'src/components'),'@utils': path.resolve(__dirname, 'src/utils'),'@assets': path.resolve(__dirname, 'src/assets'),},},
};

使用示例:

// 不使用别名(路径很长,容易出错)
import Button from '../../../components/Button';
import utils from '../../../../utils/helpers';
import logo from '../../../../assets/images/logo.png';// 使用别名(简洁明了)
import Button from '@components/Button';
import utils from '@utils/helpers';
import logo from '@assets/images/logo.png';

常见别名配置:

// 典型的别名配置
alias: {'@': 'src',                    // 源码目录'@components': 'src/components', // 组件目录'@pages': 'src/pages',         // 页面目录'@utils': 'src/utils',         // 工具函数目录'@assets': 'src/assets',       // 静态资源目录'@styles': 'src/styles',       // 样式文件目录'@api': 'src/api'              // API接口目录
}
3.2.2 static 目录

什么是static目录?
static目录是存放不需要构建处理的静态文件的地方。

特点:

  • 文件会被直接复制到输出目录
  • 不会被构建工具处理(如压缩、转换等)
  • 通常用于存放第三方库、字体文件等

目录结构示例:

project/src/           ← 源码目录(会被构建)static/        ← 静态资源目录(直接复制)libs/        ← 第三方库jquery.min.jsbootstrap.cssfonts/       ← 字体文件roboto.woff2images/      ← 图片文件logo.pngpublic/        ← 公共资源目录(有些项目用这个)

使用方式:

<!-- 在HTML中引用static目录的文件 -->
<script src="/libs/jquery.min.js"></script>
<link href="/fonts/roboto.css" rel="stylesheet" />
<img src="/images/logo.png" />
3.2.3 assets 目录

什么是assets目录?
assets目录通常存放需要构建工具处理的资源文件。

特点:

  • 文件会被构建工具处理(压缩、优化等)
  • 文件名会添加hash值(用于缓存控制)
  • 通常用于存放项目自己的资源

目录结构示例:

src/assets/        ← 资源目录(会被构建处理)images/      ← 图片hero.jpg   → 构建后变成 hero.a1b2c3.jpgstyles/      ← 样式文件main.css   → 构建后变成 main.d4e5f6.cssicons/       ← 图标文件home.svg

使用方式:

// 在JavaScript中引用assets目录的文件
import heroImage from '@/assets/images/hero.jpg';
import './assets/styles/main.css';// 构建工具会自动处理路径和文件名

3.3 构建工具如何处理路径

3.3.1 Webpack路径处理流程

1. 开发阶段:

// webpack.config.js
module.exports = {devServer: {static: './dist', // 静态文件目录proxy: {'/api': 'http://localhost:3000', // API代理},},
};

2. 构建阶段:

// webpack.config.js
module.exports = {output: {path: path.resolve(__dirname, 'dist'),publicPath: '/', // 公共路径前缀},plugins: [new CopyWebpackPlugin({patterns: [{from: 'public', // 源目录to: '.', // 目标目录(相对于output.path)},],}),],
};

3. 路径转换过程:

源码中的路径: @/components/Button↓
别名解析: src/components/Button↓
模块解析: 找到实际文件↓
构建输出: dist/js/main.abc123.js(包含Button组件代码)
3.3.2 Vite路径处理

配置示例:

// vite.config.js
export default {resolve: {alias: {'@': path.resolve(__dirname, 'src'),'@assets': path.resolve(__dirname, 'src/assets'),},},build: {outDir: 'dist',assetsDir: 'assets', // 资源文件输出目录},
};

4. 后端路径处理

4.1 静态文件服务

4.1.1 Express.js静态文件服务

基本配置:

const express = require('express');
const path = require('path');
const app = express();// 提供静态文件服务
app.use(express.static('public'));// 现在可以访问:
// http://localhost:3000/images/logo.png
// http://localhost:3000/css/style.css
// http://localhost:3000/js/app.js

多目录静态文件服务:

// 为不同路径提供不同目录的静态文件
app.use('/images', express.static('public/images'));
app.use('/css', express.static('public/css'));
app.use('/js', express.static('public/js'));
app.use('/fonts', express.static('public/fonts'));// 现在可以访问:
// http://localhost:3000/images/logo.png  → public/images/logo.png
// http://localhost:3000/css/style.css   → public/css/style.css
// http://localhost:3000/js/app.js       → public/js/app.js
4.1.2 高级静态文件配置

带缓存控制的静态文件服务:

// 设置缓存头
app.use('/static',(req, res, next) => {// 设置1年缓存res.setHeader('Cache-Control', 'public, max-age=31536000');next();},express.static('public')
);// 条件请求处理
app.use('/static',(req, res, next) => {const filePath = path.join(__dirname, 'public', req.path);if (fs.existsSync(filePath)) {const stats = fs.statSync(filePath);const etag = `"${stats.mtime.getTime()}-${stats.size}"`;// 检查If-None-Match头if (req.headers['if-none-match'] === etag) {return res.status(304).end();}res.setHeader('ETag', etag);}next();},express.static('public')
);

4.2 路由映射

4.2.1 路径映射原理

什么是路由映射?
路由映射就是将URL路径映射到实际的文件或处理函数。

映射示例:

// URL路径 → 实际文件路径
'/css/style.css''public/css/style.css'
'/js/app.js''public/js/app.js'
'/images/logo.png''public/images/logo.png'
'/api/users'         → 处理函数(不是文件)

实现方式:

// 1. 使用express.static自动映射
app.use(express.static('public'));// 2. 手动映射
app.get('/css/*', (req, res) => {const filePath = path.join(__dirname, 'public', req.path);res.sendFile(filePath);
});// 3. 使用中间件映射
app.use('/assets', express.static('public/assets'));
4.2.2 动态路径处理

处理动态路径:

// 处理带参数的路径
app.get('/images/:category/:filename', (req, res) => {const { category, filename } = req.params;const filePath = path.join(__dirname, 'public/images', category, filename);if (fs.existsSync(filePath)) {res.sendFile(filePath);} else {res.status(404).send('File not found');}
});// 访问示例:
// /images/avatars/user1.jpg → public/images/avatars/user1.jpg
// /images/products/item.png → public/images/products/item.png

4.3 文件系统路径

4.3.1 路径拼接最佳实践

使用path模块:

const path = require('path');// ❌ 错误:字符串拼接
const filePath = __dirname + '/public/images/logo.png';// ✅ 正确:使用path.join
const filePath = path.join(__dirname, 'public', 'images', 'logo.png');// ✅ 更安全:使用path.resolve
const filePath = path.resolve(__dirname, 'public', 'images', 'logo.png');
4.3.2 路径处理工具函数

安全的文件路径处理:

// 安全的文件路径处理
function getStaticFilePath(relativePath) {// 规范化路径,防止路径遍历攻击const normalizedPath = path.normalize(relativePath);// 确保路径在允许的目录内const allowedDir = path.resolve(__dirname, 'public');const fullPath = path.resolve(allowedDir, normalizedPath);// 检查路径是否在允许的目录内if (!fullPath.startsWith(allowedDir)) {throw new Error('Path traversal attack detected');}return fullPath;
}// 使用示例
app.get('/static/*', (req, res) => {try {const filePath = getStaticFilePath(req.path);res.sendFile(filePath);} catch (error) {res.status(400).send('Invalid path');}
});

5. 前后端协调最佳实践

5.1 开发环境配置

5.1.1 前端开发服务器配置

Webpack Dev Server配置:

// webpack.config.js
module.exports = {devServer: {port: 8080,static: './dist',// 代理API请求到后端proxy: {'/api': {target: 'http://localhost:3000',changeOrigin: true,},},},
};

Vite开发服务器配置:

// vite.config.js
export default {server: {port: 8080,proxy: {'/api': {target: 'http://localhost:3000',changeOrigin: true,},},},
};
5.1.2 后端开发服务器配置

Express开发服务器:

// server.js
const express = require('express');
const cors = require('cors');
const app = express();// 允许跨域请求(开发环境)
app.use(cors({origin: 'http://localhost:8080', // 前端开发服务器地址})
);// API路由
app.use('/api', apiRoutes);// 静态文件服务
app.use(express.static('public'));app.listen(3000, () => {console.log('后端服务器运行在 http://localhost:3000');
});

5.2 生产环境配置

5.2.1 一体化部署方案

目录结构:

project/dist/              ← 前端构建输出index.htmlcss/js/images/server.js          ← 后端服务器package.json

后端服务器配置:

// server.js
const express = require('express');
const path = require('path');
const app = express();// 提供前端静态文件
app.use(express.static('dist'));// API路由
app.use('/api', apiRoutes);// 所有非API请求都返回index.html(SPA路由)
app.get('*', (req, res) => {res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});app.listen(3000, () => {console.log('服务器运行在 http://localhost:3000');
});
5.2.2 分离部署方案

前端部署:

# 构建前端
npm run build# 部署到CDN或静态文件服务器
# 前端访问地址:https://myapp.com

后端部署:

// 后端服务器配置
const express = require('express');
const cors = require('cors');
const app = express();// 允许前端域名访问
app.use(cors({origin: 'https://myapp.com',})
);// API路由
app.use('/api', apiRoutes);app.listen(3000, () => {console.log('API服务器运行在 http://localhost:3000');
});

前端配置:

// 前端API配置
const API_BASE_URL =process.env.NODE_ENV === 'production'? 'https://api.myapp.com' // 生产环境API地址: 'http://localhost:3000'; // 开发环境API地址// 使用示例
fetch(`${API_BASE_URL}/api/users`);

5.3 路径配置最佳实践

5.3.1 统一路径管理

前端路径配置:

// config/paths.js
const config = {development: {API_BASE_URL: 'http://localhost:3000',STATIC_BASE_URL: 'http://localhost:8080',},production: {API_BASE_URL: 'https://api.myapp.com',STATIC_BASE_URL: 'https://cdn.myapp.com',},
};export default config[process.env.NODE_ENV];

后端路径配置:

// config/server.js
const config = {development: {port: 3000,staticDir: 'dist',uploadDir: 'uploads',},production: {port: process.env.PORT || 3000,staticDir: 'dist',uploadDir: 'uploads',},
};export default config[process.env.NODE_ENV];
5.3.2 环境变量管理

环境变量文件:

# .env.development
NODE_ENV=development
API_BASE_URL=http://localhost:3000
STATIC_BASE_URL=http://localhost:8080# .env.production
NODE_ENV=production
API_BASE_URL=https://api.myapp.com
STATIC_BASE_URL=https://cdn.myapp.com

使用环境变量:

// 前端使用
const apiUrl = process.env.REACT_APP_API_BASE_URL;// 后端使用
const port = process.env.PORT || 3000;

6. 常见问题与解决方案

6.1 问题1:图片显示不出来(404错误)

症状:

<img src="/images/logo.png" alt="Logo" />
<!-- 控制台显示:GET http://localhost:3000/images/logo.png 404 (Not Found) -->

可能原因:

  1. 文件路径错误
  2. 服务器没有配置静态文件服务
  3. 文件不存在

解决方案:

// 1. 检查文件是否存在
const fs = require('fs');
const path = require('path');const imagePath = path.join(__dirname, 'public', 'images', 'logo.png');
if (fs.existsSync(imagePath)) {console.log('文件存在');
} else {console.log('文件不存在');
}// 2. 配置静态文件服务
app.use(express.static('public'));// 3. 检查文件权限
fs.access(imagePath, fs.constants.R_OK, err => {if (err) {console.log('文件不可读');} else {console.log('文件可读');}
});

6.2 问题2:开发环境正常,生产环境出错

症状:

  • 开发环境一切正常
  • 生产环境资源加载失败

可能原因:

  1. 构建配置问题
  2. 服务器配置问题
  3. 路径映射问题

解决方案:

// 1. 检查构建输出
console.log('构建输出目录:', path.resolve(__dirname, 'dist'));// 2. 检查服务器配置
app.use(express.static('dist', {index: false, // 不自动提供index.htmlsetHeaders: (res, path) => {console.log('提供文件:', path);},})
);// 3. 添加错误处理
app.use((err, req, res, next) => {console.error('静态文件服务错误:', err);res.status(500).send('Internal Server Error');
});

6.3 问题3:跨域问题

症状:

Access to fetch at 'http://localhost:3000/api/users' from origin 'http://localhost:8080' has been blocked by CORS policy

解决方案:

// 后端配置CORS
const cors = require('cors');app.use(cors({origin: ['http://localhost:8080', 'https://myapp.com'],credentials: true,})
);// 或者手动设置CORS头
app.use((req, res, next) => {res.header('Access-Control-Allow-Origin', 'http://localhost:8080');res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');next();
});

6.4 问题4:缓存问题

症状:

  • 更新了文件,但浏览器还是显示旧内容
  • 强制刷新才能看到更新

解决方案:

// 1. 设置缓存控制头
app.use('/static',(req, res, next) => {// 开发环境不缓存if (process.env.NODE_ENV === 'development') {res.setHeader('Cache-Control', 'no-cache');} else {// 生产环境设置长期缓存res.setHeader('Cache-Control', 'public, max-age=31536000');}next();},express.static('public')
);// 2. 使用ETag
app.use('/static',(req, res, next) => {const filePath = path.join(__dirname, 'public', req.path);if (fs.existsSync(filePath)) {const stats = fs.statSync(filePath);const etag = `"${stats.mtime.getTime()}-${stats.size}"`;res.setHeader('ETag', etag);}next();},express.static('public')
);

7. 实战案例:完整项目路径配置

7.1 项目结构

my-app/
├── src/                    ← 前端源码
│   ├── components/
│   ├── pages/
│   ├── assets/
│   │   ├── images/
│   │   └── styles/
│   └── utils/
├── public/                 ← 静态资源(不构建)
│   ├── images/
│   ├── fonts/
│   └── libs/
├── dist/                   ← 构建输出
├── server/                 ← 后端代码
│   ├── routes/
│   ├── middleware/
│   └── server.js
├── webpack.config.js
└── package.json

7.2 前端配置

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');module.exports = {entry: './src/index.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'js/[name].[contenthash].js',publicPath: '/',},resolve: {alias: {'@': path.resolve(__dirname, 'src'),'@components': path.resolve(__dirname, 'src/components'),'@assets': path.resolve(__dirname, 'src/assets'),'@utils': path.resolve(__dirname, 'src/utils'),},},plugins: [new HtmlWebpackPlugin({template: './src/index.html',}),new CopyWebpackPlugin({patterns: [{from: 'public',to: '.',},],}),],devServer: {port: 8080,static: './dist',proxy: {'/api': 'http://localhost:3000',},},
};

前端代码示例:

// src/utils/api.js
const API_BASE_URL =process.env.NODE_ENV === 'production'? 'https://api.myapp.com': 'http://localhost:3000';export const fetchUsers = () => {return fetch(`${API_BASE_URL}/api/users`);
};// src/components/Header.jsx
import React from 'react';
import logo from '@assets/images/logo.png'; // 使用别名路径const Header = () => {return (<header><img src={logo} alt='Logo' /><h1>My App</h1></header>);
};export default Header;

HTML模板:

<!-- src/index.html -->
<!DOCTYPE html>
<html><head><title>My App</title><!-- 使用绝对路径引用静态资源 --><link href="/fonts/roboto.css" rel="stylesheet" /><script src="/libs/jquery.min.js"></script></head><body><div id="app"></div></body>
</html>

7.3 后端配置

server.js:

const express = require('express');
const path = require('path');
const cors = require('cors');
const fs = require('fs');const app = express();// 中间件配置
app.use(cors({origin:process.env.NODE_ENV === 'production'? ['https://myapp.com']: ['http://localhost:8080'],})
);app.use(express.json());// 静态文件服务配置
const setCacheHeaders = (res, maxAge) => {res.setHeader('Cache-Control', `public, max-age=${maxAge}`);
};// 字体文件 - 1年缓存
app.use('/fonts',(req, res, next) => {setCacheHeaders(res, 31536000);next();},express.static(path.join(__dirname, 'dist/fonts'))
);// 第三方库 - 6个月缓存
app.use('/libs',(req, res, next) => {setCacheHeaders(res, 15552000);next();},express.static(path.join(__dirname, 'dist/libs'))
);// 图片文件 - 1个月缓存
app.use('/images',(req, res, next) => {setCacheHeaders(res, 2592000);next();},express.static(path.join(__dirname, 'dist/images'))
);// CSS和JS文件 - 1年缓存
app.use(/\\.(css|js)$/,(req, res, next) => {setCacheHeaders(res, 31536000);next();},express.static(path.join(__dirname, 'dist'))
);// API路由
app.use('/api', require('./routes/api'));// 其他静态文件
app.use(express.static(path.join(__dirname, 'dist')));// SPA路由 - 所有非API请求返回index.html
app.get('*', (req, res) => {res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {console.log(`服务器运行在 http://localhost:${PORT}`);
});

7.4 部署脚本

package.json:

{"scripts": {"dev": "concurrently \"webpack serve\" \"node server/server.js\"","build": "webpack --mode production","start": "npm run build && node server/server.js","deploy": "npm run build && pm2 start server/server.js --name my-app"}
}

7.5 环境配置

开发环境:

# .env.development
NODE_ENV=development
API_BASE_URL=http://localhost:3000
STATIC_BASE_URL=http://localhost:8080

生产环境:

# .env.production
NODE_ENV=production
API_BASE_URL=https://api.myapp.com
STATIC_BASE_URL=https://myapp.com

8. 总结

8.1 关键要点

  1. 路径选择原则:

    • 公共资源使用绝对路径
    • 项目内部资源可以使用相对路径或别名
    • 构建后的资源统一使用绝对路径
  2. 前后端协调:

    • 前端负责路径引用
    • 后端负责路径映射
    • 构建工具负责路径转换
  3. 环境配置:

    • 开发环境使用代理
    • 生产环境统一部署或分离部署
    • 使用环境变量管理不同环境的配置
  4. 最佳实践:

    • 统一路径管理
    • 合理的缓存策略
    • 完善的错误处理
    • 安全的路径验证

8.2 常见错误避免

  1. 不要混用相对路径和绝对路径
  2. 不要硬编码路径
  3. 不要忽略跨域问题
  4. 不要忘记缓存控制
  5. 不要忽略安全性

通过理解这些概念和最佳实践,你就能轻松处理Web开发中的各种路径问题,让项目更加稳定和可维护!


希望这篇指南能帮助你更好地理解前后端路径处理!如果还有疑问,欢迎继续讨论。

http://www.dtcms.com/a/500222.html

相关文章:

  • 为什么网站要备案头条新闻 免费下载
  • 汇通网做期货的网站做期货的网站软件开发平台 devcloud
  • 专门做橱柜衣柜效果图的网站青海网站建设怎么建设
  • 算法沉淀第六天(牛客小白月赛122 和 Codeforces Round 1059 (Div. 3))
  • 网站建设与维护蒋勇从前端开发培训机构有哪些
  • 网站建设后的心得浙江省建设通网站
  • Git的多人协作
  • 成都开发网站建设怎么下载应用商店
  • 14-哈希SHA1案例:宝钢
  • Python数据分析:小实例,数人头
  • 单页面网站怎么做软件项目开发文档模板
  • 松岗营销型网站建设软文范例大全
  • 本地网站建设方案信息大全网站数据迁移教程
  • 麦肯锡:从「AI价值悖论」到代理式 AI 的产业化落地
  • 金华市建设技工学校教育培训网站什么是网站建设整体策划方案
  • C++动态规划入门指南——助力CSP竞赛夺冠(加强版)
  • 【前端高级特效】使用 CSS 实现毛玻璃模糊背景效果(含完整源码讲解)
  • 网站备案花钱么培训学校网站
  • 【人工智能系列:机器学习学习和进阶01】机器学习初学者指南:理解核心算法与应用
  • 利用舵机实现机器人行走
  • 做网站时需要FTP工具吗济南市工程造价信息网
  • 电商网站的特点wordpress投稿者发附件
  • CSDN:打造专业的技术名片
  • pveproxy 无响应不能访问web
  • 我怎么做个人网站做网站用html还是jsp
  • 做营销的一般逛哪些网站新网域名注册查询
  • 数据库设计原则
  • php网站开发工资网站免费建站系统
  • 大气 网站模板做网站需要多少
  • 使用MLflow跟踪和管理你的机器学习实验