我最近开始使用Twitter,并遇到了#learninpublic的这一趋势。我看到很多人记录他们的日常进度。看到其他开发人员在高技能方面相互支持是令人鼓舞的。它给了我通过博客记录我的学习的想法。所以,我在这里。
几个月前,我开始学习反应和逆风。当时,我还在考虑建立一个申请,以跟踪我的费用和预算。自然而然地,我想到的是,练习我的学习将是一个很棒的项目。所以我开始了。
我计划构建一个CRUD应用程序,可以在其中输入交易的详细信息,并且可以处理这些应用程序,以提供每月分析和累积数据。
这是我制作的,Digiledger,交易管理和费用跟踪应用程序。
这是我到目前为止集成的基本功能。
- 记录交易
- 交易过滤
- 费用和收入分析
这是链接:
实时网站:https://digiledger.vercel.app/
前端存储库:https://github.com/AnshumanMahato/Digiledger-Frontend
后端存储库:https://github.com/AnshumanMahato/DigiLedger-Backend
我有计划使用更多功能扩展该项目。但这仅此而已。本文更多地是关于我在构建这个项目时学到的东西。
建立项目以学习知识,并分享您的学习以巩固它们。
研究东西是学习任何东西的最佳方法。毫无疑问。除了学习外,它还建立了与之合作的信心。这就是这个项目对我的帮助。我发现反应速度更快,并获得了一些有趣的见解。
这是我学到的主要内容:
首先还是后端?
在我以前的项目中,我主要从事后端工作。我从来没有遇到任何问题,因为我有必须工作的准则。我得到了终点,他们的要求和他们的回答列表。所以这从来都不是问题。
这是我第一次开始从头开始构建所有内容。作为一个后端家伙,我首先跳了起来。而且非常麻烦。我已经弄清楚了终点。困难的是找出请求和响应结构。
随着后端的工作变得累人,所以我切换到了前端。那时事情变得很清楚。知道我们如何呈现数据使我们对收到和发送的内容有清晰的了解。
我与一些开发人员谈到了他们的工作流程。一些人从设计和前端部分开始,使用模拟API。准备好基本结构后,它们移至后端。然后根据需要继续来回切换。其他人说他们先做了后端,然后整合了前端。
起初,我认为这一定是“ ”的东西。但是一旦思考,我终于明白了。首先不是前端或后端。它的计划需要先完成。
计划设计,模型,体系结构等,并在一开始对它们进行记录对于开发过程至关重要。它们为应用程序提供了边界。它简化了应用程序的范围。
我也意识到我的设计技巧不是很好。我需要做一些工作。ð
使用效应的工作
在文章和教程中,我对使用效应的最初理解是,其中的函数首先执行,然后基于依赖项数组来调用。我以为这一切都是顺序发生的。
让我们看看以下示例。
import "./styles.css";
import { useEffect, useRef } from "react";
export default function App() {
const testArr = useRef();
useEffect(() => {
testArr.current = ["kratos", "atreus", "mimir", "sindri", "brok"];
}, []);
return (
<div className="App">
{testArr.current.map((el) => (
<p>{el.toUpperCase()}</p>
))}
</div>
);
}
如果我根据自己的最初理解,这就是它的执行方式。首先,声明testarr,然后使用使用效率执行,然后渲染组件。
和男孩,我错了。控制台向我发送了问候“无法阅读未定义的属性(阅读'Map')。
我做了很多思考并尝试了不同的解决方案,但没有任何效果。但是后来令我震惊。所有文章和教程始终将函数称为使用效率回调。我终于了解发生了什么。首先,我们声明了Testarr最初未定义。然后使用效法执行,将回调的上下文对回调队列。然后渲染组件。此后,当执行堆栈变为空时,从回调队列中选出回调并执行。然后,根据价值变化重新渲染组件。
所以testArr = useRef([])
解决了问题。起初,这是一个尤里卡(Eureka)的时刻,但后来我感到愚蠢的是没有彻底浏览资源。
我从所有这些中学到的是对使用效应的良好理解,以及为什么要对国家和参考文献进行适当的初始化至关重要。
在跨站点的情况下与httponly cookie合作
我正在使用JWT令牌进行身份验证。将其存储在本地存储中,使其容易受到XSS(跨站点脚本)攻击的攻击,因此我正在使用Httponly Cookie。概念是,一旦我们从主机中收到HTTPonly cookie,只要浏览器拥有它,浏览器就会将其发送给该主机。由于客户端脚本无法访问httponly cookie,因此它可以防止XSS攻击。
我在以前的大多数项目中都使用了这种策略。它总是很好。但是这一次,它无效。浏览器正在接收曲奇,但没有将其发送回。浏览器控制台或服务器上都没有错误。我搜索了“浏览器不将cookie发送到服务器”,但什么都没有。
尽管我没有发现任何解决方案,但仍提到了CORS政策,原始标题,Samesite和CSRF对基于Cookie的身份验证的攻击。我的前端和后端是独立的应用程序。他们在不同的港口工作,所以这是一个跨点的情况。因此,即使我对此不了解,我也有一个预感,这可能是问题(我是对的)。
我们知道,我们将HTTPonly Cookie发送到每个请求的主机。默认情况下,仅当客户端和服务器在同一域上时才发生。如果我将前端作为静态文件服务,那将有效。或者,如果我像以前的项目一样使用了服务器端渲染。但是,我们必须针对跨站点请求明确指定此。在Axios中,我们设置了withCredentials
配置字段。
axios.get(BASE_URL + '/todos', { withCredentials: true });
// default for all requests
axios.defaults.withCredentials = true
// only with a group of requests
const instance = axios.create({
withCredentials: true,
baseURL: BASE_URL
})
instance.get('/todos')
在Fetch API中,我们使用credentials
Config Field。它需要其中之一
三个值,
- 如果您只想在请求URL与调用脚本相同的原点时发送凭据,请添加
credentials: 'same-origin'
。 - 使浏览器发送带有凭据同时包含凭证和交叉呼叫的凭据的请求,请添加
credentials: 'include'
。 - 为了确保浏览器在请求中不包含凭据,请使用
credentials: 'omit'
。
fetch("https://example.com", {
credentials: "include",
});
我们将Access-Control-Allow-Credentials
响应标头设置为true在我们的服务器上。
,但即使在此之后,它也无效。经过一番研究,我发现这是由于保护CSRF攻击所致。
CSRF代表跨站点资源伪造。让我们以一个例子理解这一点。假设一个系统位于www.front.com
处的前端,而后端位于www.back.com
。我们打算做的是将API称为from www.front.com
至www.back.com
。但是,假设用户访问了骗局网站www.trustmebiro.com
。它默默地对www.back.com
进行了一些API调用。在允许跨站点的情况下,这可以正常工作,因为我们只需要令牌cookie进行身份验证。因此,我们为意外客户提供未经授权的访问权限,并容易受到数据泄露的影响。
可以在cookie选项中设置SameSite
属性,以防止CSRF攻击。它可以采用任何值,
-
Strict
-您的cookie只能在第一方上下文中发送。用用户术语,浏览器仅在cookie网站与当前在浏览器的URL栏中显示的站点匹配的网站时发送cookie。但是,在遵循指向您网站的链接时,从另一个网站或通过朋友的电子邮件说,浏览器不会在该初始请求下发送cookie。当您拥有与功能有关的cookie时,这始终是初始导航的后面,例如更改密码或进行购买,但这太过限制了。 -
Lax
-如果您的读者遵循链接到该站点,他们希望发送cookie,以便可以应用他们的偏好。这就是SameSite=Lax
的来源,允许浏览器以这些顶级导航发送cookie。 -
None
-使用此选项,浏览器将随着所有请求发送cookie,而不论原点如何。但是这样,cookie必须具有Secure
属性。它确保我们仅通过HTTPS连接发送cookie。另外,我们需要在我们的CORS政策中包括The Access-Control-Allow-Origin
。
最后一个选择是我要做的。因此,毕竟,我终于使自己的应用程序按照预期的方式工作。这很乏味。但是我学到了很多有关互联网攻击,CORS政策,服务器配置和网络的知识。
取消组件上的请求
之后,该应用程序的最低功能完成了。所以我部署了它。我使用免费服务来部署我的应用程序,因此性能很慢。它使我思考了连接缓慢的用户。
我的应用程序中没有加载屏幕。因此,没有迹象表明发生了什么事。因此我做了一个。这也让我思考,如果用户在请求持续时尝试导航怎么办?到响应来了,他们将在另一个页面上。它将没有用。因此,我开始寻找在组件卸载时取消悬而未决请求的方法。我必须了解AbortController
。
根据MDN,AbortController
接口代表一个控制器对象,允许您在需要时按照或多个Web请求中止。它具有属性signal
和一个实例方法abort()
。
这是我们将其与Axios一起使用的方式。
const controller = new AbortController();
axios
.get('/foo/bar', { signal: controller.signal })
.then(function(response) {
//...
});
// cancel the request
controller.abort();
尽管这看起来很简单,但我面临着将其与React集成的困难。到目前为止,我已经弄清楚了如何为我们在使用效率回调中提出的请求实施它。这就是我们的方式。
import axios from "axios";
import {useEffect} from "react";
function Component() {
useEffect(()=>{
const controller = new AbortController();
(async()=>{
const response = await axios.get('www.example.com',{
signal: controller.signal,
})
//further manipulations
})();
return ()=>controller.abort();
});
return (<div>
{/*Component body*/}
</div>)
}
我仍然需要弄清楚如何根据用户操作(例如登录或交易创建)触发的请求。我正在研究它。如果您有任何建议,请在评论中告诉我。
好吧,这就是伙计们!
这就是我迄今为止通过这个项目收集的一切。正如我之前说的那样,这是一次很棒的学习经历。我需要弄清楚更多的东西。我需要在这个项目上做很多工作。但是到目前为止我做的一切都很有趣。
我希望这个博客对您有见地。如果您对任何事情有任何建议或反馈,请评论。或者您也可以在Twitter上与我联系。我的手柄是@AnshumanMahato_。
感谢您阅读这篇文章。 ð