0%

前言

通常我们用Cloudflare WARP通过替换VPS的双栈或单栈网络来通过获得所谓“原生IP”,从而解锁Netflex等流媒体,而如果直接替换掉双栈网络会导致VPS失联,即使通过修改路由表正常使用也会影响到Docker等应用的NAT。实际上我们只需要让Xray的流量走WARP接口出去就行了,outbounds配置提供了sendThrough用来指定出口IP,streamSettings.sockopt.mark用来设置fwmark。我之前直接指定为WARP的IP发现并不行,收不到回包(实际上如果直接指定接口名就正常使用了,可惜不支持)。在翻Xray的文档时才发现还需要配置一下路由表才行。

使用sendThrough

阅读全文 »

通常我们会通过spring的异常处理器来自定义响应格式,即通过@RestControllerAdvice来实现,但是如果只是为了自定义一个返回格式的话有更好的选择,那就是自定义ErrorController,所有未被处理的异常都会被它处理,@RestControllerAdvice也被视为异常处理,即被@RestControllerAdvice处理的异常将不会到达这里,直接上代码,以Kotlin为例

@RestController
@RequestMapping("/error")
class GlobalErrorController : ErrorController {

    @Autowired
    lateinit var errorAttributes: ErrorAttributes

    @GetMapping
    fun error(request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        val ex: Throwable? = errorAttributes.getError(ServletWebRequest(request))
        val status = getStatus(request)
        return ResponseEntity.status(status)
            .body(ErrorResponse(status = status.name, message = ex?.localizedMessage ?: ""))
    }

    private fun getStatus(request: HttpServletRequest): HttpStatus {
        val statusCode = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)

        if (statusCode !is Int) {
            return HttpStatus.INTERNAL_SERVER_ERROR
        }

        return try {
            HttpStatus.valueOf(statusCode)
        } catch (e: Exception) {
            HttpStatus.INTERNAL_SERVER_ERROR
        }
    }
}
  • 这里注入了一个ErrorAttributes类型的bean,它包含了请求上下文的错误信息,通过getError方法可以获取到异常类

  • 匹配到路由/error的方法的返回值会作为响应发送到客户端,当然这个路由是可以自定义的

阅读全文 »

由于ohmyzsh的复杂和臃肿,导致其启动速度不尽人意,并且第三方插件的安装和管理需要手动进行,所以打算用zinit来代替ohmyzsh,以获得更好的性能以及使用体验

安装

使用官方提供的脚本

阅读全文 »

实现类似于zsh和fish的命令高亮和提示效果
QQ截图20210807135714.png

Set-PSReadLineOption -PredictionSource History
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineOption -Colors @{ InlinePrediction = "#666666" }
Set-PSReadLineOption -BellStyle none
Set-PSReadLineOption -HistorySearchCursorMovesToEnd

直接上代码

open class BaseController<T : BaseEntity>(val baseService: BaseService<T>) {

    @Transactional
    @AuthRequired
    @PatchMapping("/{id}")
    open fun updateById(@PathVariable("id") id: Long, @RequestBody entity: T): ResponseEntity<T> {
        entity.id = id
        return ResponseEntity.ok(baseService.updateById(entity))
    }

}

访问controller时出现NullPointerException,此时baseService为null

阅读全文 »

在尝试用kotlin写springboot项目时发现springboot的kotlin项目模板的注解处理器没生效,结果就是自定义的配置类在idea中没有语法提示,且有一堆黄线警告,解决方法就是用kapt进行注解处理
在build.gradle.kts加入

plugins {
    ...
    kotlin("kapt") version "1.4.20"
}

dependencies {
    ...
    kapt("org.springframework.boot:spring-boot-configuration-processor")
}

重新构建,这样就能正确生成spring-configuration-metadata.json

阅读全文 »

在MySQL中,当使用timestamp作为储存时间的类型时,其读写都与sessiontime_zone有关。当没有显式指定时,当前session的time_zone会继承全局设置

  • 当写入时,会根据当前session的time_zone转换成UTC时间,将其时间戳进行储存
  • 当读取时,会将UTC时间戳转换为session所设置的time_zone所对应的时间

根据其他资料在连接字符串中添加参数serverTimezone

阅读全文 »

编辑/etc/gai.conf

找到如下部分,取消前5行的注释

# label   <mask>   <value>
#    Add another rule to the RFC 3484 label table.  See section 2.1 in
#    RFC 3484.  The default is:
#
label ::1/128       0
label ::/0          1
label 2002::/16     2
label ::/96         3
label ::ffff:0:0/96 4
#label fec0::/10     5
#label fc00::/7      6
#label 2001:0::/32   7
阅读全文 »

利用statik库将静态资源嵌入二进制,但是GIN并没有提供从http.FileSystem加载模板的方法,所以得手动去加载

主要实现

func initTemplates() *template.Template {
	statikFS, err := fs.New()
	if err != nil {
		log.Fatal(err)
	}
	t := template.New("")
	//找出所有扩展名为.gohtml的文件,将其解析为模板
	err = fs.Walk(statikFS, config.TemplateDir, func(path string, info os.FileInfo, err error) error {
		if filepath.Ext(info.Name()) == ".gohtml" {
			f, err := statikFS.Open(path)
			if err != nil {
				return err
			}

			b, err := ioutil.ReadAll(f)
			if err != nil {
				return err
			}

			_, err = t.New(path[1:]).Parse(string(b)) //此处去掉 path 前的 / 来作为模板的文件名
			if err != nil {
				return err
			}
		}

		return nil
	})

	if err != nil {
		log.Println("Load templates error")
		log.Fatal(err)
	}
	return t
}
阅读全文 »