首页 > 其他分享 >工作笔记(8)

工作笔记(8)

时间:2024-06-06 22:35:03浏览次数:17  
标签:context return 请求 Redis 笔记 工作 key string

Program.cs

启用OpenAPI支持:(Swagger支持)
顶级语句:
使用控制器:miniAPI

HTTP与HTTPS的区别

1.HTTPS协议需要到CA申请证书,一般免费的证书比较少,因而需要一定费用。

2.HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的SSL加密传输协议。

3.HTTP和HTTPS使用的是完全不同的链接方式,用的端口也不一样,前者是80端口,后者是443端口。

4.HTTP的链接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。

.Net 6 Program.cs设计模式 :建造者模式

23种设计模式之一 用于创建复杂对象,将复杂对象的创建和使用分离

中间件:中间件是一种装配到应用管道以处理请求和响应的软件
  • 选择是否将请求传递到管道中的下一个组件。
  • 可在管道中的下一个组件前后执行工作。

顺序:通过(请求委托-带着请求上下文)一级一级往下传递

ExceptionHandler=>HSTS(HTTPStrictTranspostSecurity)=>HttpsRedirection=>StaticFiles=>Routing=>CORS=>Authentication=>Authorization=>Custom middlewares=>Endpoint

DI是IOC的实现

ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,这是一种在类及其依赖关系之间实现控制反转(IOC)的技术。

跨域

后端跨域:

AllowAnyOrigin:允许所有的请求源(需要设置白名单)

.WithOrigins(" ","192.168.1.1",...)

AllowAnyMethod:允许所有的请求方法

AllowAnyHeader:允许所有的请求头

前端跨域(vue.config.js):

项目文件
bin

bin用来保存项目生成后程序集,是默认情况下的输出文件目录,也就是你的工程编译的结果(dll或者exe),包括其它你设置了需要输出的文件,比如:配置,资源文件等内容。这个文件夹是默认的输出路径,我们可以通过:项目属性—>配置属性—>输出路径来修改。

.cs+.csproj = bin/Debug/.Net 6/.dll

obj

用来保存每个模块的编译结果,在.NET中,编译是分模块进行的,编译整个完成后会合并为一个.DLL或.EXE保存到bin目录下。因为每次编译时默认都是采用增量编译,即只重新编译改变了的模块,obj保存每个模块的编译结果,用来加快编译速度。是否采用增量编译,可以通过:项目属性—>配置属性—>高级—>增量编译来设置

switch新语法糖

query = flag switch
            {       
                //1=> query.OrderBy(x => x.销量),
                2 => query.OrderBy(x => x.Price),
                //3 => query.OrderByDescending(x => x.销量),
                4 => query.OrderByDescending(x => x.Price),
                _ => query.AsQueryable(),
            };

部署

部署是分发要安装到其他计算机上的已完成应用程序或组件的过程。对于控制台应用程序或基于 Windows 窗体的智能客户端应用程序,有两个部署选项可供选择:ClickOnce 和 Windows Installer。

Docker

请求头和响应头

请求头

由四部分组成:首行、header(头)、空行、body(存放url参数)。
首行:传参方法(GET或POST)+url+版本号(例如Http1.1)。
header :由多组参数(key-value)构成。
空行:标志着header的结束。
body:如果传参方法为GET,那么body为空,如果为POST那么传送的参数都在body中。
Accept:浏览器可接受的MIME类型。
Accept-Charset:浏览器可接受的字符集。
Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。
Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。
Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。
Connection:表示是否需要持久连接。如果 Servlet 看到这里的值为“Keep-Alive”,或者看到请求使 用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个 元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答 中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后 在正式写出内容之前计算它的大小。
Content-Length:表示请求消息正文的长度。
Content-Type:也叫互联网媒体类型( Internet Media Type )或者 MIME 类型,在 HTTP协议消息 头中,它用来表示具体请求中的媒体类型信息。例如, text/html 代表 HTML 格式, image/gif 代表 GIF 图片, application/json 代表JSON 类型
Cookie:设置cookie,这是最重要的请求头信息之一
Host:头字段用于指示请求的目标主机的主机名或IP地址。
From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。 Host:初始URL中的主机和端口。
If-Modified-Since:只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答。
Pragma(/ˈpræɡmə/):指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经 有了页面的本地拷贝。
Referer:包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。
User-Agent(/ˈeɪdʒənt/):浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。
UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU。

响应头

Accept-Patch:指定服务器所支持的文档补丁格式
Accept-Ranges:服务器所支持的内容范围
Content-Disposition:对已知MIME类型资源的描述,浏览器可以根据这个响应头决定是对返回资源的动作,如:
将其下载或是打开。
Content-Encoding:响应资源所使用的编码类型。
Content-Language:响就内容所使用的语言
Content-Length:响应消息体的长度,用8进制字节表示
Content-Type:当前内容的MIME类型
Date:此条消息被发送时的日期和时间(以RFC 7231中定义的"HTTP日期"格式来表示)
Expires:指定一个日期/时间,超过该时间则认为此回应已经过期
Server:服务器的名称

根据规格返回相应SKU

public GoodDTO GetSKU(int goodId, string? skuValue)
        {
            string jsonValue = "";
            Dictionary<string, string> dic = new Dictionary<string, string>();
            if (skuValue != null)
            {
                string json = skuValue.Trim(',');
                var jsonArray = json.Split(',');
                foreach (var item in jsonArray)
                {
                    var keys = item.Split(':');
                    dic[keys[0]] = keys[1];
                }
                jsonValue = JsonConvert.SerializeObject(dic);
            }
            var entity = (from a in _context.SKUs
                          join b in _context.Goods on a.GoodId equals b.GoodId
                          where (string.IsNullOrEmpty(jsonValue) || a.SKU_Name == jsonValue) &&
                          a.GoodId == goodId
                          select new GoodDTO
                          {
                              GoodId = a.GoodId,
                              GoodName = b.GoodName,
                              Price = a.Price,
                              Picture = a.Picture,
                              SKU_No = a.SKU_No,
                              SKU_Description = a.SKU_Description,
                              Stock = a.Stock,
                              BuyCount = 0
                          }).FirstOrDefault();
            return entity ?? new GoodDTO();

路由

请求URL映射到控制器方法的过程,这个映射过程由路由规则定义。

Routing is responsible for matching incoming HTTP requests and dispatching those requests to the app's executable endpoints. Endpoints are the app's units of executable request-handling code. Endpoints are defined in the app and configured when the app starts. The endpoint matching process can extract values from the request's URL and provide those values for request processing. Using endpoint information from the app, routing is also able to generate URLs that map to endpoints.

自定义登录验证中间件

//Program.cs开启内存缓存
builder.Services.AddMemoryCache();

编写自定义中间件:(异步)

//A task that represents the completion of request processing
        //用来执行下一个中间件
        private readonly RequestDelegate _next;
        private readonly IMemoryCache _cache;
        /// <summary>
        /// 构造方法注入
        /// </summary>
        /// <param name="next"></param>
        /// <param name="cache"></param>
        public LoginMiddleware(RequestDelegate next, IMemoryCache cache)
        {
            _next = next;
            _cache = cache;
        }
//Invoke 方法固定 编写中间件的逻辑
        //Task 异步返回值
        //HttpContext Http上下文对象--包含请求和响应的所有信息
        public async Task InvokeAsync(HttpContext context)
        {
            //判断当前URL地址是否为购物车的地址
            if (context.Request.Path == "/api/Good/ShoppingCartAdd")
            {
                //如果是购物车的地址,判断当前用户是否登录
                string token = _cache.Get<string>("token");
                //如何判断你是否登录了呢?
                if (string.IsNullOrEmpty(token))
                {
                    //如果没有登录,就返回一个错误消息
                    await context.Response.WriteAsync("Please log in first!");
                    context.Response.StatusCode = 500;
                    //前台使用响应拦截器处理
                    return;
                }
                //(http协议,请求时无状态)如果登录了,验证前后台token是否一致
                var requestToken = context.Request.Headers["token"];
                if (token != requestToken)
                {
                    await context.Response.WriteAsync("you have no permission!");
                    context.Response.StatusCode = 401;
                    return;
                }
                //如果登录了,就执行下个中间件                
            }
            await _next(context);
        }

使用中间件:

//自定义中间件
app.UseMiddleware<LoginMiddleware>();

用户登录:请求和响应使用不同的DTO(RequestLoginDTO和ResponseLoginDTO),保护用户数据

/// <summary>
        /// 用户登录(企业)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult UserLogin(RequestLoginDTO request)
        {
            ApiResult apiResult;
            if (request == null)
            {
                return NotFound("对象无效");
            }
            if (string.IsNullOrEmpty(request.UserName))
            {
                return NotFound("用户名为空");
            }
            if (string.IsNullOrEmpty(request.UserPwd))
            {
                return NotFound("密码为空");
            }
            var result = _services.UserLogin(request.UserName, request.UserPwd);
            if (result == null)
            {
                apiResult = new ApiResult()
                {
                    Code = 500,
                    Msg = "登录失败",
                };
                return Ok(apiResult);
            }
            else
            {
                ResponseLoginDTO response = new ResponseLoginDTO()
                {
                    UserId = result.UserId,
                    UserName = result.UserName,
                    Name = result.Name,
                };
                apiResult = new ApiResult()
                {
                    Code = 200,
                    Msg = "登录成功",
                    Data = response,
                };
                string token = _services.CreateTokenString();
                //string token = $"{result.UserId}-{DateTime.Now.Ticks}";
                //正常情况下,token应该存储到redis中,这里为了方便,直接存储到内存中
                _cache.Set("token", token);
                apiResult.Token = token;
                return Ok(apiResult);
            }
        }

异步编程(Asynchronous Programming)

避免阻止线程,增加 Web 应用程序中的吞吐量,从而释放线程来为 Web 应用程序中的其他请求提供服务。

异步(底层是状态基,是由多个状态的调度完成)不一定是多线程,有可能是多线程,多线程一定不是异步
多线程的弊端:线程安全、资源占用。

等待多个任务完成

Axios拦截器(interceptor)

定义:在请求或响应被 then 或 catch 处理前拦截它们

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  });

用Hash类型将数据缓存到Redis中

private List<GoodDTO> SetCartRedis(int userId)
        {
            var query = from a in _context.ShoppingCarts
                        join b in _context.SKUs on a.SKU_No equals b.SKU_No
                        join c in _context.Goods on b.GoodId equals c.GoodId
                        where a.UserId == userId
                        select new GoodDTO
                        {
                            Stock = b.Stock,
                            GoodId = b.GoodId,
                            SKU_No = a.SKU_No,
                            GoodName = c.GoodName,
                            Picture = b.Picture,
                            Price = b.Price,
                            BuyCount = a.BuyCount,
                            TotalAmount = a.TotalAmount,
                            UserId = a.UserId,
                        };
            var list = query.ToList();
            //将数据存储到Redis中
            //设置随机过期时间,防止缓存雪崩
            //var random = new Random();
            //var randomNumber = random.Next(3, 5);
            //_client.Set("carts", list, randomNumber);
            //存    		
    		_client.HSet("Carts", userId.ToString(), list);
            //取
            //var list = _client.HGet<List<GoodDTO>>("Carts", userId.ToString());
            return list;
        }
Redis五大类型

Redis 非关系型数据库

字符串类型是Redis中最基本的数据存储类型,它是一个由字节组成的序列,在Redis中是二进制安全的。这意味着该类型可以接受任何格式数据,如JPEG图像数据和Json对象说明信息。它是标准的key-value,通常用于存储字符串、整数和浮点。Value可容纳高达512MB的数据。

Redis hash 是一个键值(key=>value)对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。Redis的Hash结构可以使你像在数据库中Update一个属性一样只修改某一项属性值。和String略像,但value中存放的是一张表,一般用于多个个体的详细事项排列,String也可以做到,但要比hash麻烦许多。

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。Redis的列表允许用户从序列的两端推入或者弹出元素,列表由多个字符串值组成的有序可重复的序列,是链表结构,所以向列表两端添加元素的时间复杂度为0(1),获取越接近两端的元素速度就越快。这意味着,即使有数以千万计的元素列表,也可以极快地获得10条记录在头部或尾部。可列入名单的要素最多只有4294967295个。

Redis 的 Set 是 string 类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 0(1)。所谓集合就是一堆不重复值的组合,并且是没有顺序的。在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还提供了诸如collection、union和differences等操作,使得实现诸如commandism、poperhike、secondfriends这样的功能变得很容易,或者选择是将结果返回给客户机,还是将它们保存到使用不同命令的新的集合中。

sorted set也叫Redis zset ,和set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。

Computed和Methods的区别

Computed可以把计算结果缓存,如果监听的数据源发生变化,才会重新计算,否则直接使用缓存的数据

缓存的优点:引入缓存可以提高系统性能、减少网络传输、缓解服务器负载、支持离线访问、保护原始数据以及提供数据一致性。

Linq左外连接

var list = (from a in _context.Goods
                        join b in _context.SKUs on a.GId equals b.GId into c
                        from sku in c.DefaultIfEmpty()
                        group sku by new { a.GId, a.GName, a.GPicture, a.GPrice } into d
                        select new
                        {
                            d.Key.GId,
                            d.Key.GName,
                            d.Key.GPicture,
                            d.Key.GPrice,
                            TotalStock = d.Sum(x => x.SKUStock)
                        }).ToList();
            return list;

反射

 //定义一个获取反射内容的方法
       void getreflectioninfo(assembly myassembly)
       {
             type[] typeArr=myassemby.Gettypes();//获取类型
             foreach (type type in typeArr)//针对每个类型获取详细信息
            {
                   //获取类型的结构信息
                  constructorinfo[] myconstructors=type.GetConstructors;
                 //获取类型的字段信息
                 fieldinfo[] myfields=type.GetFiedls()
                 //获取方法信息
                 MethodInfo myMethodInfo=type.GetMethods();
                 //获取属性信息
                 propertyInfo[] myproperties=type.GetProperties
                 //获取事件信息
                 EventInfo[] Myevents=type.GetEvents;
           }
      }

加载(loading)

//线程休眠
Thread.Sleep(2000);
<!--服务方式-->
openFullScreen2() {
        const loading = this.$loading({
          lock: true,
          text: 'Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        });
		<!--访问API-->
        setTimeout(() => {
          loading.close();
        }, 2000);
      }

多字段排序(Linq.Dynamic)

​ .NET中OrderBy和ThenBy的语义是不同的,如:list.OrderBy(x=>x.A).OrderBy(x=>x.B),那么最终只会根据B进行排序;list.OrderBy(x=>x.A).ThenBy(x=>x.B),那么最终会先根据A、再根据B进行排序,类似sql中的order by 语句。
​ 这里使用动态LINQ
​ 1、下包System.Linq.Dynamic.Core
​ 2、using System.Linq.Dynamic.Core

if (!string.IsNullOrEmpty(orderRules))
{
    var ruleArray = orderRules.Split(',');
    string orderString = "";
    for (int i = 0; i < ruleArray.Length; i++)
    {
        //销量
        if (ruleArray[i] == "1")
        {
            ruleArray[i] = "SaleCount desc";
        }
        //单价
        if (ruleArray[i] == "2")
        {
            ruleArray[i] = "GPrice desc";
        }
        orderString += ruleArray[i] + ',';
    }
    //Func<Good, object> sortBy = x =>new {x.SaleCount desc,x.GPrice desc}
    orderString = orderString.Trim(',');
    list = list.AsQueryable().OrderBy(orderString).ToList();

SQL循环添加测试数据

declare @i int
set @i=1
while(@i<15)
begin
	insert into Goods values (CONCAT('测试数据',@i),'0','0','','',GetDate(),'4')
	set @i+=1
end

vue获取来源路由

beforeRouteEnter(to, from, next) {
    // ...
    next((vm) => {
      vm.originPath = from.path;
    });
  },
// 在组件内部使用
this.$router.push({ path: '/destination', query: { from: this.$route.fullPath }}); // 跳转到目标页面并传递来源路由信息
 
// 在目标页面中获取来源路由
mounted() {
   const sourceRoute = this.$route.query.from; // 获取来源路由信息
}

vue封装公共操作前端页面缓存方法(sessionStorage、localStorage、cookie)

export const session = {
    set(key, value) {
        window.sessionStorage.setItem(key, value);
    },
    get(key) {
       return window.sessionStorage.getItem(key);
    },
    remove(key) {
        window.sessionStorage.removeItem(key);
    }
}
export const local = {
    set(key, value) {
        window.localStorage.setItem(key, value);
    },
    get(key) {
       return window.localStorage.getItem(key);
    },
    remove(key) {
        window.localStorage.removeItem(key);
    }
}
import {session,local} from "../../store/storageHelper.js"

ASP.Net内置对象

Request
Response
Server
Session
Cookie
Application

Swagger原样输出

//原样输出
services.AddControllers().AddNewtonsoftJson(options => {
// 忽略循环引用
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
// 不使用驼峰
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
// 设置时间格式
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
// 如字段为null值,该字段不会返回到前端
// options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});

VS.NET(C#)-5.16_IIS6架构模型:HTTP.SYS简介

标签:context,return,请求,Redis,笔记,工作,key,string
From: https://www.cnblogs.com/keepingstudying/p/18236202

相关文章

  • 工作笔记(7)
    SQL事务begintransactiondemo--开始事务+事务名 begintry insertinto[User]values('tianqi','123456','田七','false','2001-09-22','','0','false',NULL,'false') insertin......
  • 大模型学习笔记-汇总篇
    本文记录一下最近一个月学习的大模型相关的技术知识点,为拥抱AI浪潮做些技术储备。大模型术语相关参数规模GPT3.5千亿级别GPT41.8W亿级别国内一般都是十亿或百亿级别ChatGLM2_2K_6BBAICHUAN_4K_13B淘宝星辰_4K_13BTOKEN长度Token是指被LLM处理的离散的数据单......
  • 工作笔记(6)
    快捷键替换选中内容:Ctrl+HCtrl+Alt+Enter退出终端:Ctrl+Cvue初始化格式:Vueinit设置路由:router/index/js{path:"/studentInfo",name:"studentInfo",component:()=>import("../views/Student/StudentView.vue")}布局页:APP.vueEmmit语法......
  • 工作笔记(10)
    SignalR微软官方文档TMS关键字:大车GPS交通局短信休息15分钟/4小时火星坐标=>大地坐标(如果要用百度地图还要将大地坐标=>百度坐标)电子围栏①模拟制造数据(预制路线):C/S架构1条/5秒非关系型数据库/时序数据库 17280条/日/车SignalR:长连接 API主动同步数据到客户端案例......
  • 数据结构学习笔记-归并排序
    归并排序算法的设计与分析问题描述:设计并分析归并排序算法【算法设计思想】分割(Divide):从中间分割数组,使每个子数组包含一半的元素。这通过计算中点m来完成,通常是(l+r)/2,但为了防止大数溢出,使用l+(r-l)/2。解决(Conquer):递归地对两个子数组应用归并排序,直到......
  • 算法学习笔记(21):数论分块
    数论分块大部分内容来源于OI-WIKI引理1:\(\\foralla,b,c\in\mathbb{Z},\left\lfloor\frac{a}{bc}\right\rfloor=\left\lfloor\frac{\left\lfloor\frac{a}{b}\right\rfloor}{c}\right\rfloor\)引理2:\(\lfloor\frac{n}{i}\rfloor\)的取值有\(O(\sqrtn)\......
  • 【YOLOv8改进】DAT(Deformable Attention):可变性注意力 (论文笔记+引入代码)
    YOLO目标检测创新改进与实战案例专栏专栏目录:YOLO有效改进系列及项目实战目录包含卷积,主干注意力,检测头等创新机制以及各种目标检测分割项目实战案例专栏链接:YOLO基础解析+创新改进+实战案例摘要Transformers最近在各种视觉任务中展现出了优越的性能。较大甚至是......
  • 部分数论学习笔记
    数论分块若可以\(O(1)\)计算\(f(r)-f(l)\),那么就可以\(O(\sqrtn)\)计算\(\sum^n_{i=1}f(i)(g\lfloor\frac{n}{i}\rfloor)\)。关于\(l,r\)的含义与计算:含义:\(\forallx\in[l,r],\lfloor\frac{n}{x}\rfloor\)相等计算:刚开始\(l\)肯定为\(1\),如何理解\(r=......
  • 微前端学习笔记(5):从import-html-entry发微DOM/JS/CSS隔离
    import-html-entry 是qiankun中一个举足轻重的依赖,用于获取子应用的HTML和JS,同时对HTML和JS进行了各自的处理,以便于子应用在父应用中加载。 import-html-entry主要是实现了以下几个能力拉取url对应的html并且对html进行了一系列的处理拉取上述html中所......
  • 微前端学习笔记(1):微前端总体架构概述,从微服务发微
    从最初的CS架构,如MFCJavaSwing等,到BS架构,JSPPHP,再到前端后端分离,前端从jquery  GWT-Ext 到Handlebars,再到angularJS/Vue/React,反观java世界,学好SpringMyBatis,一路无忧,哎…… 微服务为了解决庞大的一整块后端服务带来的变更与扩展方面的限制,出现了微服务架构(Mic......