摸鱼快报:golang net/http中的雕虫小技

摸鱼,快报,golang,net,http,雕虫小技 · 浏览次数 : 222

小编点评

**雕虫小技快报** **1. 创建 React 项目** - 使用 Create React App 脚手架创建 React 项目。 - 配置项目,设置默认端口为 3000。 **2. 设置后端服务器** - 使用 Go 框架 gin 创建后端服务器。 - 使用 8034 端口启动服务器。 - 配置跨域请求,设置 `domain` 属性为 `localhost:3000`。 **3. 配置前端服务器** - 在 `package.json` 中配置后端地址。 - 设置前端地址为 `localhost:8034`。 **4. 处理跨域请求** - 设置 `SameSite` 属性为 `lax`。 - 在 `Login` 模块中设置认证 Cookie 的策略。 **5. 处理请求超时** - 使用 `io.ReadAll` 读取响应内容,设置超时时间。 - 如果响应时间超过设置的超时时间,返回错误。 **6. 处理状态码** - 在服务器端设置状态码,并将其作为响应头的值返回。 - 如果状态码不是 200,返回错误。 **7. 探索 `statuscode`** - `statuscode` 是一个作为 HTTP 响应状态码的字符串。 - 在 Go 语言中,`statuscode` 通常作为 `Header` 值返回。 - 在 fasthttp 中,使用 `SetRequestURI` 设置请求 URI,`SetMethod` 设置请求方法,`SetRequestURI` 设置请求路径。

正文

以后会开一个板块,摸鱼快报,快速记录这几周开发中雕虫小技。

1. 向开发环境localhost:3000种植cookie

前端使用Create React App脚手架,默认以localhost:3000端口启动;
后端使用golang-gin框架,使用8034端口启动。
登录模块走的是sso,前后端分离,后端需要向前端写入认证cookie

c.SetSameSite(http.SameSiteLaxMode)
c.SetCookie("userInfo", userInfoMapString, 60*60*12, "/", cfg.CookieDomain, false, false)
c.SetCookie("access_token", accessToken.(string), 60*60*12, "/", cfg.CookieDomain, false, false)

若种植cookie时设置domain=localhost:3000,实际会发现该cookie被种为domain=localhost

① golang给出日志提示:2023/01/12 19:10:48 net/http: invalid Cookie.Domain "localhost:3000"; dropping domain attribute, 该cookie domain被丢弃:

② 如果该cookie没有domain,该Cookie称之为HostOnly Cookie,后续请求只有host与cookie的domain完全相等,才能携带这个cookie。

react配置后端地址,要配置为localhost:8034,而不能是127.0.0.1:8034

经此一役:

  • 源(Origin)是由 URL 中协议、主机名(域名 domain)以及端口共同组成的部分
  • 本次出现的问题在于两个关键cookie属性 :
    • cookie domain: cookie被种植到哪个域名下?
    • cookie samesite: 请求哪些资源domain时能携带该cookie?

2. httpclient timeout报错经验

golang net/http httpclientTimeout:
Timeout specifies a time limit for requests made by this Client. The timeout includes connection time, any redirects, and reading the response body. The timer remains running after Get, Head, Post, or Do return and will interrupt reading of the Response.Body.

HttpClient Timeout包括连接、重定向(如果有)、从Response Body读取的时间,内置定时器会在Get,Head、Post、Do 方法之后继续运行,并有能力中断读取Response.Body.


如果upstream服务器处理超时(upstream_response_time> client设置的timeout),则会返回context deadline exceeded (Client.Timeout exceeded while awaiting headers)

如果客户端使用io.ReadAll读取body超时,则会返回context deadline exceeded (Client.Timeout or context cancellation while reading body)

3. url 大小写敏感

大家使用net/http 建立的http server,默认的请求url path是大小写敏感的:

s.mux.HandleFunc("/leader", func(w http.ResponseWriter, r *http.Request) {

}

s.mux.HandleFunc("/LEADER", func(w http.ResponseWriter, r *http.Request) {

}

以上会被认定为不同的路由path。
探究源码:ServeMux使用map[string]muxEntry 哈希表来存储路由。


这与aspnet core的路由行为是不一样的,/hello、/HELLO都会命中下面的路由。

 app.UseEndpoints(endpoints =>
 {  
    endpoints.MapGet("/hello", async context =>
      {
         await context.Response.WriteAsync("Hello!");
      });
}

w3c官方建议: url大小写敏感

URLs in general are case-sensitive (with the exception of machine names). There may be URLs, or parts of URLs, where case doesn't matter, but identifying these may not be easy. Users should always consider that URLs are case-sensitive。
大意是说: 除了domain主机名是大小写不敏感,url一般被认为是大小写敏感。

stackoverflow有更清晰的描述

The scheme and host are case-insensitive and normally provided in lowercase; all other components are compared in a case-sensitive manner.

4. golang statuscode被作为header,一直很费解。

在 Go 语言中,客户端请求信息都封装到了Request对象,但是发送给客户端的响应并不是 Response 对象,而是ResponseWriter

func Home(w http.ResponseWriter, r *http.Request)  {
    io.WriteString(w, "Welcome to my blog site")
}

ResponseWriter是处理器用来创建 HTTP 响应的接口,其源码结构如下所示:

type ResponseWriter interface {
   // 用于设置/获取所有响应头信息
	Header() Header
   // 用于写入数据到响应实体
	Write([]byte) (int, error)
   // 用于设置响应状态码
	WriteHeader(statusCode int)
}

WriteHeader这个方法名有点误导,其实它并不是用来设置响应头的,该方法支持传入一个整型数据用来表示响应状态码,如果不调用该方法的话,默认响应状态码是 200 OK。

在fasthttp中,设置请求谓词:req.Header.SetMethod("POST"), 这种将谓词作为header的行为,我也是服气。
在fasthttp中, fasthttp.Request.SetRequestURI(uri) uri 需要带上 http:// schema
在fasthttp中, 默认的请求MIME是: application/x-www-form-urlencoded

只能设置一次statuscode, 若多次设置statuscode,以前者优先。

例如尝试以如下方式:

http.NotFound(w, r)   # 会调用WriteHeader(404);Write()写入body
w.WriteHeader(http.StatusInternalServerError)

会产生一个告警:2023/01/06 19:19:43 http: superfluous response.WriteHeader call from main.ProxyHandler (proxy.go:25), 同时产生404状态码。

可以采用如下方式清晰定义状态码和body

w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintln(w, "404 page not found")

本周摸鱼快报,阅读时间3min;难度星:3(满星5星);价值度:3(满分5分)。

与摸鱼快报:golang net/http中的雕虫小技相似的内容:

摸鱼快报:golang net/http中的雕虫小技

以后会开一个板块,摸鱼快报,快速记录这几周开发中雕虫小技。 1. 向开发环境localhost:3000种植cookie 前端使用Create React App脚手架,默认以localhost:3000端口启动; 后端使用golang-gin框架,使用8034端口启动。 登录模块走的是sso,前后

JAVA中三种I/O框架——BIO、NIO、AIO

一、BIO(Blocking I/O) BIO,同步阻塞IO模型,应用程序发起系统调用后会一直等待数据的请求,直至内核从磁盘获取到数据并拷贝到用户空间; 在一般的场景中,多线程模型下的BIO是成本较低、收益较高的方式。但是,如果在高并发的场景下,过多的创建线程,会严重占据系统资源,降低系统对外界响应

docker部署java项目

1、首先你需要提前准备好jar包或者war包,并想办法放入Linux环境(或虚拟机)中; 2、java项目的部署需要用到Tomcat或者Jetty,docker可以直接拉取他俩的镜像,这里以Tomcat为例: # : 后面需要加上war或者jar对应的Tomcat版本,最好加上, # 否则默认最新的

VMware与Windows主机之间复制粘贴

其实就是安装VMware Tools,但不知道为什么我的VMware Workstation不能安装VMware Tools,记得之前有次安装过,但是失败了。 基于apt-get命令下载安装其实是更好的选择: sudo apt-get install open-vm-tools sudo apt-g

Linux下JDK的安装配置

一、官网下载JDK1.8 https://www.oracle.com/java/technologies/oracle-java-archive-downloads.html JDK1.8 因为1.8是目前项目中用到最多的 基本都是基于JDK1.8 可以直接在虚拟机中的浏览器访问下载,但是尝试过的

浅谈Code Review

# 1. 什么是Code Review Code Review(CR)即代码评审,又名代码走查,是指对软件开发过程中编写的代码进行检查和评估的一种实践。它通常由其他团队成员、同事或专门的质量保证团队成员来执行。Code Review的目的是发现代码中的潜在问题、改进代码质量和可维护性,并确保代码符合

浅谈DevOps

# 1. DevOps概述 ## 1.1 定义 DevOps(Development and Operations)是一种软件开发和运维的方法论和实践,旨在通过加强开发团队和运维团队之间的协作和整合,提高软件交付和运维的效率、可靠性和质量。 传统上,开发团队负责软件开发、功能实现和变更管理,而运维团

@RequiredArgsConstructor和@Authwired

我们在java后端书写接口时,对service层成员变量的注入和使用有以下两种实现方式: **1) @RequiredArgsConstructor** ``` import lombok.RequiredArgsConstructor; import org.springframework.web

MySQL开发规范

> 阿里巴巴开发手册https://developer.aliyun.com/special/tech-java # 一、建表规约 **1.1表达是与否概念的字段,必须使用is_xxx的方式命名,数据类型是unsigned tinyint(1表示是,0表示否)。** tip:POJO(Domin)类

SQL调优

**1. 索引优化:** 确保适当的索引在数据库表上创建,以加快查询性能。分析查询语句,确定可能需要的列和联合索引,并避免过多或不必要的索引。 **2. 优化查询语句:** 优化查询语句的写法,避免**全表扫描**和不必要的数据检索。使用合适的WHERE子句、JOIN语句和子查询,以提高查询效率。