NUDTcourse开发日志

NUDTcourse开发日志

这不是软件计划书or升级日志,是写给自己的报告:记录知识点、相关工具的配置和使用、debug过程。

目的:记录开发收获,便于回顾总结,力求简练。

NUDTcourse是数据库课要求的一个信息管理系统项目,前后端分离,使用react、LNMP。


导出excel

后端:POI、easyExcel(都是java)

前端:js实现⬇

js文件操作之——导出Excel (js-xlsx) - youryida - 博客园 (cnblogs.com)

基于前端JS导出Excel文件(减轻服务端压力) - 云+社区 - 腾讯云 (tencent.com)

bug: API接口问题

描述:当时误认为php未正确接收表单。

详细:萌新不知道怎么做API测试,打开网络能看到预检(这是第一次听说预检是啥)成功了,后面加一个请求到的文件,但是点开啥都没。

当时的写法(是正确的。记得json要转字符串):

1
2
3
4
5
6
7
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})

php接收

1
2
3
4
5
6
7
<?php
// // 获取请求
$data = file_get_contents("php://input");
$data = json_decode($data,true);
...
echo "$Sno, $Sname, $Sgender, $Sbirth, $Major";
?>

自己写了个测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
<body>
<button onclick="fn()">.</button>
<div id="t"></div>
<script>
url = ".../test.php";
fn = function() {
fetch(url, {
method: 'POST',
mode: 'cors', //跨域
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({...})
})
.then((rp) => rp.text())
.then((response) => {
console.log(response);
document.getElementById('t').innerHTML = response;
});
}
</script>
</body>
...

测试发现发送其实成功了,如果直接点网络里请求的php文件是什么都看不到的,误判了。

test-html-ajax成功

当时的回应用console.log才能看,原来sql语句错了,取到的变量两边加上单引号。。

结论:自己不熟悉的项目or框架变数太多,可以自己做一个小demo重现bug。当时直接在项目里改,不知道bug出在ajax还是react,范围太大无处下手。

bug: php中文乱码

  • php从数据库取的数据是??

    解决:php里加上mysqli_query($con,"SET NAMES 'utf8mb4'");

  • php的array转码后变成了unicode码:{"S1":"\u59d3\u540d":"\u8d75\u4ea6","\u6027\u522b":"\u5973","\u5e74\u9f84":"17","\u7cfb\u522b":"\u5973"}...

    解决:给json_encode加上第二个参数JSON_UNESCAPED_UNICODE

php json_encode 中文不转码-php教程-PHP中文网

PHP json_encode函数的参数说明 - 范仁义 - 博客园 (cnblogs.com)

前端路由react-routerV6

后端配置问题

场景:生产环境,切换页面时向后端发送了请求,但因为那个url是做的前端路由,后端找不到页面,返回服务器的404页面。

——为什么在开发环境没有发生404呢?本地启动react项目也是给配了服务器的(像vue用了express),而项目给你把这个服务器配好了。但是生产环境本来是后端路由的,需要手动来配。

  • 要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
  • 给个警告:这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件,404的URL规则自然是交给前端路由来决定了。你应该在 Vue (React)应用里面覆盖所有的路由情况,然后再给出一个 404 页面

tomcat配置:直接修改了conf/web.xml,暴力解决(但是控制台还能看见404报错)。

tomcat返回404-修改web.xml

【我以为只会跳到index.html,结果router开始工作,路由到了正确的页面。助かる。。】

参考:

说一说前端路由与后端路由的区别 - 前端南玖 - 博客园 (cnblogs.com)

HTML5 History 模式 | Vue Router (vuejs.org)

解决单页应用 history 模式下部署 tomcat 刷新页面出现 404 - 瞭月 (lervor.com)

js主动使用路由

一般是在页面Link元素配路由,但有时候需要用js实现跳转(比如提交表单后跳转/刷新页面)。

V6文档提供的方法如下,没玩会,目前用的是原生方法。

  • 组件必须是函数Hook类型,不能是class类型
  • 2这里,useNavigate要在组件里调用,不能套在它的函数里调用

我的遭遇:

  • 使用上面官方的功能,发现没法跳转到当前页面实现刷新。但是为了重新渲染表格,我先跳到首页再跳回来,白白跳转了两次。而且如果使用返回键前进键,会发现网页的乱跳行为,很影响体验orz

  • 不用这个用原生可以吗?试了reload()location.reload()不行,**window.location.href="XXX"可以**,那就用这个了。

  • V5已经不能用this.props.history了的样子。V6更是改,直接搜博客大多过时了

局部结论:中途把凑合能用的东西强制套上去,浪费了时间。没学完没法避免,但是尽量不要到处套自己会的某方法,有时间要先查查官方想让你怎么做。

参考:

React Router | API Reference

警告:非法 Hook 调用 – React (reactjs.org)

npm

npm常用命令及参数详解 - SegmentFault 思否

使用“npm init”初始化项目 - 你是远方 - 博客园 (cnblogs.com)

Art-template

一开始使用了art-template,换react后就用jsx处理了,主要就是循环生成列表、表格,其他功能不太用的上。

模板引擎 – art-template 现在还有学习模版引擎的必要吗

前端模版引擎 - artTemplate 【上】 - 简书 (jianshu.com) (有两个详细的demo!!)

前端模版引擎 - art-template 【下】 - 简书 (jianshu.com)

  • template(temid, json)如果接收不到json或者第二个参数其实是空的,返回的不是渲染好的html而是编译了一个渲染函数(看见函数里边有的字符都被转义了还有很多\n,不懂,懵逼)
  • 如果返回回来的 JSON 数据是类似数组数据的话,是没有办法直接渲染的。需要对数据做如下包装,才能正常渲染:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template:
<tbody>
{{each student value}}
<tr>
<td>{{value.studentNumber}}</td>
<td>{{value.name}}</td>
<td>{{value.gender}}</td>
<td>{{value.age}}</td>
<td>{{value.major}}</td>
</tr>
{{/each}}
</tbody>

json格式:
{"student": php返回的json数组,里面每组的参数:studentNumber、name...}

js

如何将json对象转成数组??? - SegmentFault 思否

js字符串的裁剪 - 狗尾草的博客 - 博客园 (cnblogs.com)

JSON使用变量

1
2
3
4
5
6
// 定义空对象
let json = {};
// 使用变量作为key,只能这种写法,否则变量名会被当成字符串
// 例如json.k,作用和json = { k: "value" }、json.k = "value"一样
let k = "。。。";
json[k] = "value";

异步问题

本来写成两个函数loadrender结果render接受不到json。

ajax是典型的异步编程,必须学会回调函数、then(关于promise)。等前面语句运行完有了结果,再执行下面的。

Promise.prototype.then() - JavaScript | MDN (mozilla.org)

1
2
3
4
5
6
7
8
9
function render(tempID, url, id) {
fetch(url)
.then(response => response.json())
.then(function(data) {
let html = template(tempID, { "student": data });
document.getElementById(id).innerHTML = html;
console.log({ "student": data });
});
}

php

php字符串拼接 - museluo - 博客园 (cnblogs.com)

多行字符串

1
2
3
4
5
6
7
8
9
10
11
<?php
$str=<<<STR
'ok',"hello"
I will
{$str1}
STR;

/****
其中三个小于号代表多行字符串的输入,STR是字符串界定符,界定符的名字可以自己定义,两个界定符之间的内容就是多行字符串。其中的单引号双引号可以直接输出而不必转义,当然里面也可以直接插入变量,输出是会自动替换变量值的
****/
?>

管理技巧

MVP产品原则

开发一个最小的可行产品,从而快速试错。每次迭代,焦点都在核心流程上

前后端对接

RESTful

⚠还未良好实践

鉴权

⚠还未良好实践

HMAC

hmac主要应用在身份验证中,如下是它的使用过程: 1. 客户端发出登录请求(假设是浏览器的GET请求) 2. 服务器返回一个随机值,并在会话中记录这个随机值 3. 客户端将该随机值作为密钥,用户密码进行hmac运算,然后提交给服务器 4. 服务器读取用户数据库中的用户密码和步骤2中发送的随机值做与客户端一样的hmac运算,然后与用户发送的结果比较,如果结果一致则验证用户合法。

在这个过程中,可能遭到安全攻击的是服务器发送的随机值和用户发送的hmac结果,而对于截获了这两个值的黑客而言这两个值是没有意义的,绝无获取用户密码的可能性,随机值的引入使hmac只在当前会话中有效,大大增强了安全性和实用性。

安全

https

分离方式

  1. 半分离式,前端负责开发页面,通过接口(AJAX)获取数据跟页面进行数据绑定(类似原来的JSP标签方式),最终是由前端把页面渲染出来,后端只提供数据接口,前端的页面仍需要跟后端服务部署到同一个web容器中,如果web容器挂掉,那么会直接导致页面访问不了
  2. 全分离式, 前端负责的内容同上,只是前端页面单独部属在一个web容器,前端和后端相互不影响,如果是后端容器挂了,前端可以访问,只是请求不到数据
  3. 还有一种就是 在前端和后端之间加入node作为服务,node提供一些接口服务,又或者部分页面需要服务端渲染,又或者需要处理一些大并发的问题,如果是需要涉及到一些大数据的查询或者运算,再由node层去跟后端服务(java服务等)进行数据交互,再由node 接口供给前端

用了react后可以全分离也可以都放在nginx下(前端使用的接口是绝对地址,跨域也解决了)

后端是通过nginx挂载php的fastcgi,接收前端发来的请求,对数据库进行相关操作。

前端和后端数据交互的基本知识和常见方式

  • 用 form 可以发请求,但是会刷新页面或新开页面;
  • 用 a 可以发 get 请求,但是也会刷新页面或新开页面;
  • 用 img 可以发 get 请求,但是只能以图片的形式展示;
  • 用 link 可以发 get 请求,但是只能以 CSS、favicon 的形式展示;
  • 用 script 可以发 get 请求,但是只能以脚本的形式运行。
  • 用 jsonp 实现请求,支持跨域请求。
  • 用 ajax 实现页面无刷新的请求。

ajax技术

XMLHttpRequest,结构比较混乱(但出现很久了,使用规模巨大);fetch,新兴的ajax技术(他俩是平起平坐的关系)。axios库是对XHR的封装,而上面两个是原生api。

综合考虑开发难度和兼容性问题,决定选用axios进行前后端的信息交互。 用了fetch原生。

双向通信

WebSocket与消息推送 - 张果 - 博客园 (cnblogs.com)

如何在大型 Web 应用中保持数据的同步更新? - 知乎 (zhihu.com)

轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。 优点:后端程序编写比较容易。 缺点:请求中有大半是无用,浪费带宽和服务器资源。

实例:适于小型应用【针对管理员开启轮询怎么样orz】。

长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。 优点:在无消息的情况下不会频繁的请求,耗费资小。 缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 Comet异步的ashx,

实例:WebQQ、Hi网页版、Facebook IM。

长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。 优点:消息即时到达,不发无用请求;管理起来也相对方便。 缺点:服务器维护一个长连接会增加开销。

实例:Gmail聊天

Websocket:

WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。

特点:事件驱动、异步、使用ws或者wss协议的客户端socket,能够实现真正意义上的推送功能

缺点:少部分浏览器不支持,浏览器支持的程度与方式有区别。

跨域问题

cors跨域之简单请求与预检请求(发送请求头带令牌token) - SegmentFault 思否

使用 Fetch - Web API 接口参考 | MDN (mozilla.org)

允许跨域

配置nginx:

1
2
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: <origin>

最早被提出来的本地存储方式,在每一次 http 请求携带 Cookie,可以判断多个请求是不是同一个用户发起的,特点是:

  • 有安全问题,如果被拦截,就可以获得 Session 所有信息,然后将 Cookie 转发就能达到目的。(关于攻击和防范本可以看另一篇文章 吃透浏览器安全(同源限制/XSS/CSRF/中间人攻击))
  • 每个域名下的Cookie不能超过20个,大小不能超过4kb
  • Cookie在请求新页面的时候都会被发送过去
  • Cookie创建成功名称就不能修改
  • 跨域名不能共享Cookie

如果要跨域名共享Cookie有两个方法

  • 用 Nginx 反向代理
  • 在一个站点登录之后,往其他网站写 Cookie。服务端的 Session 存储到一个节点,Cookie 存储 SessionId

Cookie的使用场景

  • 最常见的就是 Cookie 和 Session 结合使用,将 SessionId 存储到 Cookie 中,每次请求都会带上这个 SessionId 这样服务端就知道是谁发起的请求
  • 可以用来统计页面的点击次数

Cookie都有哪些字段

  • NameSize 顾名思义
  • Value:保存用户登录状态,应该将该值加密,不能使用明文
  • Path:可以访问此 Cookie 的路径。比如 juejin.cn/editor ,path是/editor,只有/editor这个路径下的才可以读取 Cookie
  • httpOnly:表示禁止通过 JS 访问 Cookie,减少 XSS 攻击。
  • Secure:只能在 https 请求中携带
  • SameSite:规定浏览器不能在跨域请求中携带 Cookie 减少 CSRF 攻击,详细说明看这里
  • Domain:域名,跨域或者 Cookie 的白名单,允许一个子域获取或操作父域的 Cookie,实现单点登录的话会非常有用
  • Expires/Max-size:指定时间或秒数的过期时间,没设置的话就和 Session 一样关闭浏览器就失效

LNMP配置

原理太长不看:Nginx工作原理和优化总结

💥配置文件详解:Nginx和PHP的配置

php环境搭建(正确配置nginx和php)

  • Nginx 是非阻塞IO & IO复用模型,通过操作系统提供的类似 epoll 的功能,可以在一个线程里处理多个客户端的请求。Nginx 的进程就是线程,即每个进程里只有一个线程,但这一个线程可以服务多个客户端。
  • fastCGI :为了解决不同的语言解释器(如php、python解释器)与webserver的通信,于是出现了cgi协议。只要你按照cgi协议去编写程序,就能实现语言解释器与webserver的通信。如php-cgi程序。但是webserver每收到一个请求,都会去fork一个cgi进程,请求结束再kill掉这个进程。这样有10000个请求,就需要fork、kill php-cgi进程10000次。 fastcgi是cgi的改良版本。fast-cgi每次处理完请求后,不会kill掉这个进程,而是保留这个进程,使这个进程可以一次处理多个请求。

什么是正向代理与反向代理

正向代理是从客户端的角度出发,服务于特定用户(比如说一个局域网内的客户)以访问非特定的服务;反向代理正好与此相反,从服务端的角度出发,服务于非特定用户(通常是所有用户),已访问特定的服务。

URI规范

url 设计规范

管理员可以重新组织服务器上的文件系统结构,而无需改动URI,这就需要URI和真实的服务器文件系统结构之间有一个映射机制,而不是生硬的对应。

隐藏文件后缀名

带后缀名不够美观:nginx一招配置,帮你快速隐藏php后缀名

隐藏后缀名

零散的日记

12.15

封装了fetch,ajax简洁多了。想要使用RESTful 风格,用四种请求方法分别对应了增删改查。但没有用http状态码,url布置、JWT鉴权都还不会做,实在称不上RESTful。

image-20220127193105496

11.25

React 踩坑–input中的value与defaultValue - 墨西哥郊外的晚上* - 博客园 (cnblogs.com)

关于http请求规范

Using Fetch - Web APIs | MDN (mozilla.org)

reactjs - Javascript: Fetch DELETE and PUT requests - Stack Overflow

关于在GET请求中使用body_HermitSun的博客

大概只有get不该带body,其他带了都有情可原(它们改服务器数据了)

11.23

头次验收。老师建议:用java。php是做小网站的。

我的理解:php太好学了,功能上、性能上不够强。(直接用php是很简洁,所以很多功能不能实现。要想php实现和java一样的功能,也是要学很复杂的框架的)

前端打算换react了,脚手架走起。

——1.27:这时候才换的?

11.6

上完周五的数据库,重看了聂总的视频,结果从周五下午吸收到周六中午🤣

把看的网页堆这里(也有很多放到前端工具 & 概念 (wolai.com)了,要及时回顾)

10.29

师曰:直接显示个php页面上去还不行,要加Model层。
我:Model是啥?

查了巨多MVC、前后端分离、前端工程化(没写过后端,所以什么都拿到前端来搞)。又担心php是不是没有java先进,看了很多知乎上的【xxx是不是过时了】。光是看这些网页花了两三个晚上。确实学到不少,但凭现在的技术落不到实处,决定后端就用php。

收获:及时了解新技术。下面这些就算真过时了,学了对渐进入门有好处,可以帮助理解原理、学习设计方法。(拔草总是比种草有B格hh。但不同于劝退炒股,这是技术文章,看别人的批判是为了更好的了解,注意理性判断)

Spring MVC 过时了吗? - 知乎 (zhihu.com)
为什么我劝你放弃mybatis - 知乎 (zhihu.com)

10.20

开始系统写日志,顺路看到:谈谈开发日志 - 飞鸟_Asuka

刚起步时获取的信息比较杂乱,需要整理总结吸收。

10.15

BS5最佳学习网站:Bootstrap5 中文手册-俺老刘

注意时效性,网上很多v3v4的,也不声明自己什么版本。官方文档最靠谱。

评论