12月9
公司有个项目不能解析内网所以需要对本地hosts文件进行修改,添加一条本地域名解析记录,如果让客户去操作,很容易破坏掉原先的hosts文件,用户只需要以管理员权限运行即可,如果记录存在则替换掉。
由于办公电脑都使用信创麒麟的系统,所以最好做一个deb的安装包,通过程序写修改的,在信创麒麟的系统电脑下载安装即可执行。
下面是实现逻辑,要将java打包成deb安装包就需要使用jdeb的maven插件来打包。
我使用的是1.8的版本,具体配置就不贴上来了,需要的联系我。
               <artifactId>jdeb</artifactId>
                <groupId>org.vafer</groupId>
                <version>1.8</version>


package com.nine.rivers.jdeb;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.StrUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
* @Description 不破坏原有hosts文件,支持新host绑定或修改支持host解绑
* @Date 2022/12/9 16:42
* @Author heck
**/
public class HostUtil {

    public static final String LINUX = "linux";
    public static final String LINUX_HOSTS_PATH = "/etc/hosts";
    public static final String WINDIR = "windir";
    public static final String WIN_HOSTS_PATH = "\\system32\\drivers\\etc\\hosts";
    public static final String OS_NAME = "os.name";

    /**
     * 获取host文件路径
     *
     * @return
     */
    public static String getHostFile() {
        String fileName = null;
        // 判断系统
        if (LINUX.equalsIgnoreCase(System.getProperty(OS_NAME))) {
            fileName = LINUX_HOSTS_PATH;
        } else {
            fileName = System.getenv(WINDIR) + WIN_HOSTS_PATH;
        }
        return fileName;
    }
12月7
点击在新窗口中浏览此图片
使用Navicat连接SQLserver时,具体报错信息如下:

Installation of this product failed because it is not
supported on this operating system. For information on supported configurations,
see the product documentation.

点击在新窗口中浏览此图片
解决方法:
这个要安装一个叫做sqlncli_x64.msi的东西,手动安装,它在你的Navicat的安装目录下面,比如我的在:

D:\Program Files\PremiumSoft\Navicat Premium

点击在新窗口中浏览此图片

如果你的电脑是64位的,就运行安装那个64位的(我电脑是64位,就只标记出了64位的),如果是32 的就运行那个sqlncli.msi。

然后再进行Sqlserver的链接就不再提示安装出错了。
12月7
有时候我们在打字的时候打了拼音第一个字母的时候可以输入第二个字母直接变成了另外一个字,原因是因为后面的字母上有数字开启了FN+Num Lk变成了数字,变成了选择第几个汉字啦。
点击在新窗口中浏览此图片
1、第一种方法:先尝试按键盘的Fn+NumLock(有些是直接按NumLock),具体看键盘颜色就可以了
2、如果不行来这个基本都行的,请往下看:
3、第二种方法:按快捷键windows+R,打开开运行窗
4、然后在运行里输入osk后,按Enter回车键,打开屏幕键盘,
5、然后点击选项,打开设置窗口,把这个“打开数字小键盘”勾勾去掉即可。
12月5
公司有个项目需要对本地hosts文件进行修改,添加一条本地域名解析记录,如果让客户去操作,很容易破坏掉原先的hosts文件,最好是能封装成一个批处理脚本,用户只需要以管理员权限运行即可,如果记录存在则替换掉。

:: 关闭命令的回显
@echo off

:: 使用前请修改域名地址和ip地址
:: 域名地址
set url=heckjj.com
:: ip地址
set ip=192.168.1.1


:: 设置hosts文件路径
set HOSTS=C:\Windows\System32\drivers\etc\hosts
:: 判断当前路径是否存在 hosts.init 文件, 不存在则备份
if not exist %HOSTS%.init (
    copy /y %HOSTS% %HOSTS%.init && echo 系统hosts文件备份完成!
)

:: %date%=2022年12月04日
:: %time%= 9:12:38:96
:: 年 yyyy = %date:~0,4% 表示指针从左到右偏移 0 位, 然后提取 4 字符
:: 月 mm   = %date:~5,2% 表示指针从左到右偏移 5 位, 然后提取 2 字符
:: 日 dd   = %date:~8,2% 表示指针从左到右偏移 8 位, 然后提取 2 字符
set yyyymmdd=%date:~0,4%-%date:~5,2%-%date:~8,2%
:: 时 hh   = %time:~0,2% 表示指针从左到右偏移 0 位, 然后提取 2 字符
:: 分 mm   = %time:~3,2% 表示指针从左到右偏移 3 位, 然后提取 2 字符
:: 秒 ss   = %time:~6,2% 表示指针从左到右偏移 6 位, 然后提取 2 字符
set hh=%time:~0,2%
set mm=%time:~3,2%
set ss=%time:~6,2%
:: 当 hh 小于等于 9 时, 在前面补 0
if %hh% leq 9 (set hh=0%hh:~1,1%)

ECHO.############################## 修改系统hosts解析文件 ##############################
ECHO.#
ECHO.############################### %yyyymmdd% %hh%:%mm%:%ss% ###############################

set ip_domain=%ip% %url%
set tmpdir=%userprofile%\AppData\Local\Temp
type %HOSTS% |findstr /v "^#"| findstr /i "%ip_domain%"
if %errorlevel% == 0 (
  findstr /vi "%ip_domain%" %HOSTS% > %tmpdir%\hosts.tmp
  type %tmpdir%\hosts.tmp > %HOSTS%
  del /F /A /Q %tmpdir%\hosts.tmp
  echo %ip_domain% 更新成功!
) else (
  echo %ip_domain% 添加成功!
)
echo.>>%HOSTS%
echo %ip_domain% >> %HOSTS%

title 备份hosts文件
set yyyymmdd=%date:~0,4%%date:~5,2%%date:~8,2%
copy /y %HOSTS% %HOSTS%.%yyyymmdd%%hh%%mm%
echo ("%HOSTS%.%yyyymmdd%%hh%%mm%") 备份完毕,按任意键返回菜单!

title 刷新本地dns缓存并退出
echo 查看修改后的hosts文件内容,1秒后退出!
type "%HOSTS%" |findstr /v "^#"|findstr "[0-9]"
ping -n 1 127.0.0.1>nul
ipconfig /flushdns
echo 刷新本地缓存成功,即将退出!
ping -n 2 127.0.0.1>nul
echo.
exit
12月4
#使用前请修改域名地址和ip地址

#域名地址
$url="heckjj.com"
#ip地址
$ip="127.0.0.1"
$hosts="$env:windir\System32\drivers\etc\hosts"
$content=Get-Content $hosts
if( ($content |?{$_ -imatch "\s$url"}) -eq $null){
Write-Host "Adding `'$ip`  to `'$url`'"
"`n$ip $url" | Out-File -FilePath $hosts -Append -encoding ascii
Write-Host "Added success!"
}else{
$content=Get-Content $hosts | Where{$_.Indexof("$url") -eq -1}
Write-Host "update `'$ip`  to `'$url`'"
$content+="$ip $url"
$content | Set-Content  $hosts -Force
Write-Host "updated success!"
}

最终效果,第一次是增加,后面一直是替换原来的host记录,实际上是生写了,最开始的思路是找到域名所在的行删除该行,但发现行不通,根本没有获取域名所在行的方法,最后想着是通过获取文件内容时先过滤掉当前域名的记录,也就是只读取不包含该域名host记录的行,最后再追加就可以了。
12月4
最近公司有个项目需要对本地hosts文件进行修改,添加一条本地域名解析记录,如果让客户去操作,很容易破坏掉原先的hosts文件,最好是能封装成一个批处理脚本,用户只需要以管理员权限运行,然后根据菜单选择需要执行的功能即可。

1 批处理脚本
:: 关闭命令的回显
@echo off
:: 设置hosts文件路径
set HOSTS=C:\Windows\System32\drivers\etc\hosts
:: 判断当前路径是否存在 hosts.init 文件, 不存在则备份
if not exist %HOSTS%.init (
    copy /y %HOSTS% %HOSTS%.init && echo 系统hosts文件备份完成!
)

:: %date%=2022年12月04日
:: %time%= 14:45:38:96
:: 年 yyyy = %date:~0,4% 表示指针从左到右偏移 0 位, 然后提取 4 字符
:: 月 mm   = %date:~5,2% 表示指针从左到右偏移 5 位, 然后提取 2 字符
:: 日 dd   = %date:~8,2% 表示指针从左到右偏移 8 位, 然后提取 2 字符
set yyyymmdd=%date:~0,4%-%date:~5,2%-%date:~8,2%
:: 时 hh   = %time:~0,2% 表示指针从左到右偏移 0 位, 然后提取 2 字符
:: 分 mm   = %time:~3,2% 表示指针从左到右偏移 3 位, 然后提取 2 字符
:: 秒 ss   = %time:~6,2% 表示指针从左到右偏移 6 位, 然后提取 2 字符
set hh=%time:~0,2%
set mm=%time:~3,2%
set ss=%time:~6,2%
:: 当 hh 小于等于 9 时, 在前面补 0
if %hh% leq 9 (set hh=0%hh:~1,1%)

GOTO MENU
:MENU
ECHO.
ECHO.############################## 修改系统hosts解析文件 ##############################
ECHO.#
ECHO.# 1.添加域名解析
ECHO.#
ECHO.# 2.编辑hosts文件
ECHO.#
ECHO.# 3.备份hosts文件
ECHO.#
ECHO.# 4.还原hosts文件
ECHO.#
ECHO.# 5.刷新dns缓存并退出
ECHO.#
ECHO.############################### %yyyymmdd% %hh%:%mm%:%ss% ###############################
set /p="请输入您要操作的序号:"<nul
@set /p  sel=
if "%sel%"=="1"  goto add_ipdomain
if "%sel%"=="2"  goto edit_hosts
if "%sel%"=="3"  goto backup_hosts
if "%sel%"=="4"  goto reset_hosts
if "%sel%"=="5"  goto refresh_dns
PAUSE
:add_ipdomain
set /p="请输入IP地址和域名(中间以空格分隔):"<nul
@set /p  ip_domain=
type %HOSTS% |findstr /v "^#"| findstr /i "%ip_domain%\>"
if %errorlevel% == 0 (
  echo %ip_domain% 已存在,请重新添加!&& goto MENU
) else (
  echo.%ip_domain% >> %HOSTS% && echo %ip_domain% 添加成功,请按任意键返回菜单!&& pause >nul
)
goto MENU
:edit_hosts
title 编辑hosts本地域名解析文件
notepad %HOSTS%
echo 按任意键返回菜单!
pause >nul
goto MENU
:backup_hosts
title 备份hosts文件
set yyyymmdd=%date:~0,4%%date:~5,2%%date:~8,2%
copy /y %HOSTS% %HOSTS%.%yyyymmdd%%hh%%mm%
echo ("%HOSTS%.%yyyymmdd%%hh%%mm%") 备份完毕,按任意键返回菜单!
pause >nul
goto MENU
pause
:reset_hosts
title 还原hosts文件
copy /y %HOSTS%.init %HOSTS%
echo hosts文件已还原至初始状态,按任意键返回菜单!
pause >nul
goto MENU
:refresh_dns
title 刷新本地dns缓存并退出
echo 查看修改后的hosts文件内容,5秒后退出!
type "%HOSTS%" |findstr /v "^#"|findstr "[0-9]"
ping -n 5 127.0.0.1>nul
ipconfig /flushdns
echo 刷新本地缓存成功,即将退出!
ping -n 3 127.0.0.1>nul
echo.
exit

2 使用方法
2.1 功能菜单
第一次以管理员权限运行脚本会备份一份hosts.init文件,作为hosts初始文件,方便以后还原。



2.2 添加域名解析
添加域名解析这里采用的是手动输入 IP 地址 + 域名,并且会检索hosts文件里是否已经存在对应的 IP 地址和域名,如果存在,则提示用户重新添加。



2.3 编辑 hosts 文件
这里其实就是调用记事本来打开hosts文件。



2.4 备份 hosts文件
这里的备份文件是以hosts.日期时间的文件名格式来备份的。



2.5 还原 hosts文件
还原其实就是将 hosts.init 去掉后缀名,替换掉原先的 hosts 文件。



2.6 刷新 dns 缓存并退出
在刷新 dns 前,会先将 hosts 文件中的内容打印一下,然后执行刷新 dns 命令后退出脚本。

12月1

浅谈HTTP中Get与Post的区别

15:57Web开发  From: 本站原创

Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。URL全称是资源描述符,我们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的4个操作。到这里,大家应该有个大概的了解了,GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。

  1.根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的

  (1).所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。

  * 注意:这里安全的含义仅仅是指是非修改信息。

  (2).幂等的意味着对同一URL的多个请求应该返回同样的结果。这里我再解释一下幂等这个概念:

幂等(idempotent、idempotence)是一个数学或计算机学概念,常见于抽象代数中。
  幂等有一下几种定义:
  对于单目运算,如果一个运算对于在范围内的所有的一个数多次进行该运算所得的结果和进行一次该运算所得的结果是一样的,那么我们就称该运算是幂等的。比如绝对值运算就是一个例子,在实数集中,有abs(a)
=abs(abs(a))
  对于双目运算,则要求当参与运算的两个值是等值的情况下,如果满足运算结果与参与运算的两个值相等,则称该运算幂等,如求两个数的最大值的函数,有在在实数集中幂等,即max(x,x) 
= x

看完上述解释后,应该可以理解GET幂等的含义了。

  但在实际应用中,以上2条规定并没有这么严格。引用别人文章的例子:比如,新闻站点的头版不断更新。虽然第二次请求会返回不同的一批新闻,该操作仍然被认为是安全的和幂等的,因为它总是返回当前的新闻。从根本上说,如果目标是当用户打开一个链接时,他可以确信从自身的角度来看没有改变资源即可。

  2.根据HTTP规范,POST表示可能修改变服务器上的资源的请求。继续引用上面的例子:还是新闻以网站为例,读者对新闻发表自己的评论应该通过POST实现,因为在评论提交后站点的资源已经不同了,或者说资源被修改了。

 

  上面大概说了一下HTTP规范中GET和POST的一些原理性的问题。但在实际的做的时候,很多人却没有按照HTTP规范去做,导致这个问题的原因有很多,比如说:

  1.很多人贪方便,更新资源时用了GET,因为用POST必须要到FORM(表单),这样会麻烦一点。

  2.对资源的增,删,改,查操作,其实都可以通过GET/POST完成,不需要用到PUT和DELETE。

  3.另外一个是,早期的Web MVC框架设计者们并没有有意识地将URL当作抽象的资源来看待和设计,所以导致一个比较严重的问题是传统的Web MVC框架基本上都只支持GET和POST两种HTTP方法,而不支持PUT和DELETE方法。

   * 简单解释一下MVC:MVC本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器。使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。

  以上3点典型地描述了老一套的风格(没有严格遵守HTTP规范),随着架构的发展,现在出现REST(Representational State Transfer),一套支持HTTP规范的新风格,这里不多说了,可以参考《RESTful Web Services》。

 

  说完原理性的问题,我们再从表面现像上面看看GET和POST的区别

  1.GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。

  POST把提交的数据则放置在是HTTP包的包体中。

  2."GET方式提交的数据最多只能是1024字节,理论上POST没有限制,可传较大量的数据,IIS4中最大为80KB,IIS5中为100KB"??!

  以上这句是我从其他文章转过来的,其实这样说是错误的,不准确的:

  (1).首先是"GET方式提交的数据最多只能是1024字节",因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了。而实际上,URL不存在参数上限的问题HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。

  注意这是限制是整个URL长度,而不仅仅是你的参数值数据长度。[见参考资料5]

  (2).理论上讲,POST是没有大小限制的HTTP协议规范也没有进行大小限制,说“POST数据量存在80K/100K的大小限制”是不准确的,POST数据是没有限制的,起限制作用的是服务器的处理程序的处理能力。

  对于ASP程序,Request对象处理每个表单域时存在100K的数据长度限制。但如果使用Request.BinaryRead则没有这个限制。

  由这个延伸出去,对于IIS 6.0,微软出于安全考虑,加大了限制。我们还需要注意:

     1).IIS 6.0默认ASP POST数据量最大为200KB,每个表单域限制是100KB。
     2).IIS 6.0默认上传文件的最大大小是4MB。
     3).IIS 6.0默认最大请求头是16KB。
  IIS 6.0之前没有这些限制。[见参考资料5]

  所以上面的80K,100K可能只是默认值而已(注:关于IIS4和IIS5的参数,我还没有确认),但肯定是可以自己设置的。由于每个版本的IIS对这些参数的默认值都不一样,具体请参考相关的IIS配置文档。

  3.在ASP中,服务端获取GET请求参数用Request.QueryString,获取POST请求参数用Request.Form。在JSP中,用request.getParameter(\"XXXX\")来获取,虽然jsp中也有request.getQueryString()方法,但使用起来比较麻烦,比如:传一个test.jsp?name=hyddd&password=hyddd,用request.getQueryString()得到的是:name=hyddd&password=hyddd。在PHP中,可以用$_GET和$_POST分别获取GET和POST中的数据,而$_REQUEST则可以获取GET和POST两种请求中的数据。值得注意的是,JSP中使用request和PHP中使用$_REQUEST都会有隐患,这个下次再写个文章总结。

  4.POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改,而这里安全的含义是真正的Security的含义,比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存,(2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击。

  总结一下,Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求,在FORM(表单)中,Method默认为"GET",实质上,GET和POST只是发送机制不同,并不是一个取一个发!

  纯属hyddd个人总结,如有错漏请指出。:>

 

参考资料

[1].http://hi.baidu.com/liuzd003/blog/item/7bfecbfa6ea94ed8b58f318c.html

[2].http://www.blogjava.net/onlykeke/archive/2006/08/23/65285.aspx

[3].http://baike.baidu.com/view/2067025.htm

[4].http://www.chxwei.com/article.asp?id=373

[5].http://blog.csdn.net/somat/archive/2004/10/29/158707.aspx

12月1

Http协议是什么?

15:54Web开发  From: 本站原创

一、什么是Http协议

  超文本传输协议的简称,用于定义客户端与web服务器通迅的格式。

  关于【标准的HTTP协议是无状态的】,请参见:https://www.heckjj.com/post/628/

二、Http的版本区别

  1.0:客户端与web服务器建立连接后,只能获得一个web资源

  1.1:允许客户端与web服务器建立连接后,在一个连接上获取多个web资源

三、Http协议格式

1.请求:客户端向服务器发出的请求

  请求行(常为GET/POST请求方式)

    GET: (默认的请求方式),在URL地址后附带的参数,但是有限制的,其数据容量通常不能超过1K。对应的查——用于查询资源信息

    POST: 可以在请求的实体内容中向服务器发送数据,Post方式的特点:传送的数据量无限制。对应改——用于更新资源信息

  GET与POST的区别请参见https://www.heckjj.com/post/630/
  请求头:头值
  请求体
  

HTTP请求中的常用消息头

  accept:浏览器通过这个头告诉服务器,它所支持的数据类型
  Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集
  Accept-Encoding:浏览器通过这个头告诉服务器,支持的压缩格式
  Accept-Language:浏览器通过这个头告诉服务器,它的语言环境
  Host:浏览器通过这个头告诉服务器,想访问哪台主机
  If-Modified-Since: 浏览器通过这个头告诉服务器,缓存数据的时间
  Referer:浏览器通过这个头告诉服务器,客户机是哪个页面来的  防盗链
  Connection:浏览器通过这个头告诉服务器,请求完后是断开链接还是何持链接

2.响应:服务端向客户端送回的数据

  响应行( 协议/版本 状态码/状态码的解析 ) (状态行,处理的结果)
  响应头(key/value格式):对数据的描述以及告知客户端如何处理送回的数据

HTTP响应中的常用响应头(消息头)
  Location: 服务器通过这个头,来告诉浏览器跳到哪里
  Server:服务器通过这个头,告诉浏览器服务器的型号
  Content-Encoding:服务器通过这个头,告诉浏览器,数据的压缩格式
  Content-Length: 服务器通过这个头,告诉浏览器回送数据的长度
  Content-Language: 服务器通过这个头,告诉浏览器语言环境
  Content-Type:服务器通过这个头,告诉浏览器回送数据的类型
  Refresh:服务器通过这个头,告诉浏览器定时刷新

  Content-Disposition: 服务器通过这个头,告诉浏览器以下载方式打数据
  Transfer-Encoding:服务器通过这个头,告诉浏览器数据是以分块方式回送的
  Expires: -1  控制浏览器不要缓存
  Cache-Control: no-cache  
  Pragma: no-cache
  空行
  响应体

常见状态码:

  HTTP/1.1 200 OK HTTP版本1.1 状态码200 解码表示ok(2开头的都是ok
       404(客户端的错误,资源找不到)(4打头客户端错误
       405 不支持该请求(没有重写相关的方法doGet() doPost())
       500 请求的资源找到了,但服务器内部出现了错误(5开头服务器错误
       503 服务器暂时不可用
       302 重定向。带一个响应头Location(3开头都是中转相关
       304 未修改 Not Modified。告诉浏览器最后修改时间是正确最新的,节省传输成本
         (Last-Modifired (Since))当然针对的是HTML静态页面

12月1
引言:
最近在好好了解http,发现对介绍http的第一句话【http协议是无状态的,无连接的】就无法理解了:无状态的【状态】到底指的是什么?!
找了很多资料不仅没有发现有一针见血正面回答这个问题的,而且有些解释还充斥了各种错误,看着看着就觉得心里憋着一股浊气吐不出来
于是在看了很多资料之后,我一口吐出浊气,大声正面提出这个问题:http协议无状态中的【状态】到底指的是什么?!
然后开始不断探索解决这个问题。。。
最终很高兴的是我找到了让人满意的答案,先卖个关子,各位如果着急可以直接拉到最下查看

正文:http协议无状态中的【状态】到底指的是什么呢?

先来看这句话的另外两个概念:(标准的http协议是无状态的,无连接的)
标准的http协议指的是不包括cookies, session,application的http协议,他们都不属于标准协议,虽然各种网络应用提供商,实现语言、web容器等,都默认支持它
无连接指的是什么
每一个访问都是无连接,服务器挨个处理访问队列里的访问,处理完一个就关闭连接,这事儿就完了,然后处理下一个新的
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接

对于【无状态】,我看到很多隔着一层磨砂玻璃一样的模糊说法(官方或者教程里的说法),看着非常难受(但其实算是对的)(后来我发现我为什么觉得它看着难受了,因为他们引入了很多新的,而且明显是一个可能用在很多地方的广义名词,这些词最大的作用就是,混淆概念,下面我标注了)
协议对于事务处理没有记忆能力【事物处理】【记忆能力】
对同一个url请求没有上下文关系【上下文关系】
每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况【无直接联系】【受直接影响】
服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器【状态】

我必须得到确切而具体的解释!

这几点给了我下一步思考的方向:
【服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器 】这里的客户端的状态是不是确切地指服务器没有保存客户的信息呢?但显然不是啊
【HTTP无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品】我对此质疑为什么无状态就不能实现购物车呢?服务器就不能存储东西了么?
【 每次的请求都是独立的,<它的执行情况和结果>与<前面的请求>和<之后的请求>是无直接关系的】我觉得这个说法比较靠谱,但是所谓的不同请求间的没有关系,是指的请求内容没有关系,还是只是指请求本身没有关系?
请求内容没有关系只可能是服务器上不存有用户数据才可能啊,但是显然是存有的啊
请求本身没有关系,这又有什么意义呢,每一次的请求有什么价值?

根据这个方向我做了一个模拟访问实验:假如没有cookie没有session,只有http的时候,那当一个注册用户访问这个购物网站的时候,会发生这些事情:
前提情况:
服务器肯定为每个注册用户建立了数据表,记录用户的数据
http是无连接的
第一步需要登录
用户通过http把用户的用户名和密码发送给服务器,服务器把他们跟自己存有的用户资料对比,如果一致,则返回信息登录成功
然后用户点击某一商品页
这个动作相当于输入一个商品页的网址
假如商品页比较机密不对外公开,需要是用户才能访问
而虽然http能传送用户名和密码,而且刚才也输入了,还验证成功了,但是因为服务器既不会记得你登录的状态,你的客户端也不会存储你刚才输入的用户名和密码
所以因为这一次访问因为无法确定你的身份,只能访问失败
这时候如果要解决这个问题,而且没有cookie没有session,那就只能你在访问网址的同时继续带上你的用户名和密码(继续输入咯)其实就像我现在的APP一样
假设上一步的问题解决了,就是每次访问的时候都会手动输入用户名和密码,然后现在的情况是:你已经选了几件商品在你的购物车中,你想再添加一件商品,于是你点击某个商品旁边的加号
这个动作也相当于输入一个网址,网址的内容是发送一个请求,往你的购物车中加入这个商品
系统首先用你传来的用户名和密码验证你的身份,然后访问你的数据库,在其中的购物车属性下加一条数据,就是这个商品的数据
操作结束后,返回操作成功,并结束访问
OK,实验结束,看似没有cookie没有session也能凑合解决问题,其实两个操作都有很大的问题
你每访问一次需要权限的内容都需要在客户端输入用户名和密码,这一项的繁琐就不必赘述了
你的每一次操作都要与系统底层的数据库进行交互
多次少量的访问存在非常大的性能浪费。非常容易就能想到肯定是一次大量的操作更加有效率,于是就想到了缓存区
你的非重要琐碎数据也被写进数据库中,跟你的主要数据放在一起
一次次添加和删除购物车其实只是跟你这次浏览,或者叫这次会话有关,是临时的数据,跟用户的主要信息无关,它们没什么价值,纯粹的冗余数据(不排除现在有的公司觉得这种数据也有非常大的价值可以让它们巧妙的利用),用什么存放这些临时的数据,我们也很容易想到缓存区

经过这个模拟访问实验,结合前面的思考方向,我们知道了三点:
服务器上肯定存有用户的数据,你提交的增删改查它也能够处理,所以这句话中【服务器中没有保存客户端的状态】的状态并不是指用户的数据,我们的猜测不对
我们的质疑对了,无状态能实现购物车,可以通过服务器上存有的用户数据来实现
但是,使用上面这种方式实现购物车,存在三个比较大的问题。由此,我们不禁会想,这三个问题的解决是不是跟我们不确切了解的【状态】一词有关?于是,接下来我们来通过解决这三个问题来把【状态】的意义探寻下去

由上所述,我们可以在http的基础上增加一些机制来解决上面出现的三个问题
在用户端增加一个记录本是非常有必要的,正好官方加入的cookie机制跟这个一样,它的用处也确实是上面讨论的那样,一般就是用来标识访问者的身份
在服务器增加一个缓存区能同时解决后两个问题
有了这个缓存区作为一个数据缓冲,就不用一次次地访问数据库,浪费大量计算机资源,而是在最后统一归入数据库
有了这个缓存区,你就不用把临时的数据放到数据库中了,只需要在你们交流告一段落之后,再把数据整理,把有用的数据归入数据库
这里就自然引申出了一个重要的概念:会话,它作为一个缓冲存储区被从数据库中分离出来,理由并不生硬,它有其独特的重要且不可替代的作用。这个东西恰好跟官方加入的session机制一样
另外说一个非常具有迷惑性的容易让人对session的主要作用产生偏离的理解:认为session存在的价值就是给访问者分配一个sessionID代替用户名和密码,
为什么非常具有迷惑性,因为session确实做了这件事,而且也起到了很大的作用,所以它是对的,但是只对一半,而且没有涉及问题的本质,这种情况是最危险的(看似很有说服力,把你说服了,所以你很难有动力继续找下去,但是真实情况跟它有偏差,但是偏差不大,所以又很难把你说服回来,只有隐隐的不对劲,这个时候你离真实最近,也离真实最远)
那就顺便说说它为什么是对的,也就是用session做的另一件有用的事:
给每个session一个ID,一方面用来方便自己查询,另一方面把这个ID给用户,用户下一次访问的时候就可以不用用户名和密码,而是直接使用这个ID来表明自己的身份
首先,这个ID安全吗?这个ID比直接传用户名和密码安全吗?
你很容易会想到,本来用户名和密码的组合还特地设置地比较复杂,你这换一组数字就代替了,是不是太不安全了?
我们知道http协议本身是完全不加密的,如果使用用户名和密码,第一次访问是放在http头中,后边自动保存了密码就会放在cookie中,这些都完全没有加密,它的安全性基本为0,就是裸奔了,只要被窃取,那就丢失了
所以,就这个意义来讲,sessionID的安全性跟使用用户名和密码没什么区别
但是其实,虽然http本身不能加密,但是有些软件什么的,能在应用层面手动给你加密,比如QQ就会使用户名密码加临时验证码联合哈希,sessionID加一个时间戳简单加密也是非常常用的方法
而且因为sessionID本身有有效期,即使丢了,也可能很快失效,造成的损失可能没那么大,而用户名跟密码丢了,那就大了
所以总结就是:
不严格加密的sessionID和用户名和密码一样,都不太安全
但是相比较来说,sessionID要安全一些
而使用https是完全安全的
然后,使用sessionID有哪些好处
方便直接根据ID查询用户对应的session
加密的时候计算量小
安全性不会降低,甚至还更高一些

OK,通过独立地解决纯http机制会产生的问题,我们探讨了cookie和session机制的本质。而且想到:【使用http协议,服务器中不会保存客户端的状态】所产生的问题通过增加cookie和session机制解决了,是不是就意味着这个【状态】跟cookie和session的关系非常紧密?所以这个无状态指的是【没有对 本次会话 设置一个缓存区,记录这次会话的状态,缓存区包括服务器端和用户端】但好像还是没有点破关键(主要是觉得跟前面那些官方对状态的说法不太吻合,甚至没有对应关系)

忽然我想到一个问题:一个有状态的http是什么样的?
很难直接想象有状态的http是什么样,因为http这种机制是天然无状态的
那就类比一下吧,另一个天然有状态的机制叫TCP
如果有状态的意思是它的每次请求是有联系的,那么有状态的TCP的样子是:假如一份数据分了三份TCP包发送,那这个包上面会标明这是第几个包,会标明这个包跟那几个包是有联系的,有什么联系
但好像这个有状态的TCP跟我们想要的有状态的HTTP没有关系,因为即使每次http请求之间互相有联系,它也不能解决上面提到的http无状态的问题
诶,等等,好像能类比:
假如每个http连接都有一个签名,于是第一次登陆成功之后,服务器就知道了这个签名是允许登陆的,于是之后所有同样签名的http连接都能登陆,这里利用了同一个用户发出的http连接之间的同主人关系,这里解决了一个保持登录状态的问题
同样,来尝试利用这个【每次http请求之间互相有联系】来解决上面碰到的那个问题【每一次操作都要与系统底层的数据库进行交互】,但想了半天确实无法进行下去
不过我灵机一动,从另一个角度来想,好像解决了这个问题:
只有【每次http请求之间互相有联系】这个条件,无法解决【每一次操作都要与系统底层的数据库进行交互】
因为很明显,要解决【每一次操作都要与系统底层的数据库进行交互】就必须在服务器端开辟一块缓存区
不过如果你思考一下如何实现【每次http请求之间互相有联系】,你就会发现,它也需要在服务器端开辟一块缓存区
所以【在服务器端开辟一块缓存区】才是真正的条件,也就是说,它确实等价于【有状态】
而且我也找到了这个【在服务器端开辟一块缓存区】的条件跟前面那些官方对状态的说法对应的点,那就是:
通过在服务器端开辟一块缓存区,存储、记忆、共享一些临时数据,你就可以:
协议对于事务处理有记忆能力【事物处理】【记忆能力】
对同一个url请求有上下文关系【上下文关系】
每次的请求都是不独立的,它的执行情况和结果与前面的请求和之后的请求是直接关系的【不独立】【直接关系】
服务器中保存客户端的状态【状态】
所以,这个状态,加上前面说的客户端也有cookie,就是指,客户端和服务器在临时会话中产生的数据!而前面也说道了,使用缓存区保存临时会话中的数据是多么重要
所以状态不仅包括不同URL访问之间的关系,还有对其他URL访问的数据记录,还有一些其他的东西,所以更确切地说,状态应该是【实现了这些东西所凭借的后面的缓存空间】中的客户的临时数据
cookie和session应该是完全实现了有状态这个功能

一种常见的对状态的误解:
有人在解释HTTP的无状态时,把它跟有连接对立,说是两种方式,也就是如果想不无状态,就必须有连接,但其实不然
有连接和无连接以及之后的Keep-Alive都是指TCP连接
有状态和无状态可以指TCP也可以指HTTP
TCP一直有状态,HTTP一直无状态,但是应用为了有状态,就给HTTP加了cookie和session机制,让使用http的应用也能有状态,但http还是无状态
开始TCP是有连接,后来TCP无连接,再后来也就是现在TCP是Keep-Alive,有点像有连接。
12月1

Hutool工具类之Http工具

15:51Web开发  From: 本站原创
最简单最直接的上手可以参见参考文档:https://hutool.cn/docs/#/

受够了的HttpClient?那Hutool的HttpUtil值得一试!

一、HttpUtil 
快读使用:
发送get请求,包括有参与无参 
示例:
String url = "http://www.heckjj.com";
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("query", heck);
        // 无参GET请求
        String result = HttpUtil.get(url);
        // 带参GET请求
        String result2 = HttpUtil.get(url, paramMap);
      
发送post请求
这里直接引用文档的示例:

HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("city", "北京");
String result= HttpUtil.post("https://www.heckjj.com", paramMap);

//文件上传只需将参数中的键指定(默认file),值设为文件对象即可,对于使用者来说,文件上传与普通表单提交并无区别
paramMap.put("file", FileUtil.file("D:\face.jpg"));
String result= HttpUtil.post("https://www.heckjj.com", paramMap);
对应源码:


/**
     * 发送post请求
     *
     * @param urlString 网址
     * @param paramMap post表单数据
     * @return 返回数据
     */
    public static String post(String urlString, Map<String, Object> paramMap) {
        return HttpRequest.post(urlString).form(paramMap).execute().body();
    }

    /**
     * 发送post请求
     *
     * @param urlString 网址
     * @param params post表单数据
     * @return 返回数据
     */
    public static String post(String urlString, String params) {
        return HttpRequest.post(urlString).body(params).execute().body();
    }

二、HttpRequest与HttpResponse
  不满足于高度化的工具类封装,想拥有更多自定义请求与响应处理,可以使用HttpRequest与HttpResponse

快速上手:
String result2 = HttpRequest.post(url)
    .header(Header.USER_AGENT, "Hutool http")
    .form(paramMap)
    .execute().body();
分页: 4/66 第一页 上页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]