前言

学习了这么久的web技术,让我们来复习回顾一下其中的重要知识。内容比较主观,仅为个人理解!

学习笔记列表:

Web技术


WEB基础

对于WEB技术,我们首先要掌握它的一些基础概念,下面是一些重要概念。

具体部分可以看:

【WEB】WEB基本要素

首先,WEB的根本(web essentials)是建立在TCP/IP协议的基础上,一种客户端-服务器端编程架构的网络应用。TCP/IP的层次结构如下:

网络访问传输过程:

  • What is the whole process that Telnet simulates Web Client to access Web server?
    Telnet模拟Web 客户端访问Web服务器的整个过程是怎样的?

    (下面过程仅为个人答案,答案正确性不作保证!!!)

    1. Telnet客户端首先需要将Web服务器的域名解析为IP地址,它使用DNS协议在客户端和DNS服务器之间在应用层进行通信。
      The Telnet client needs to resolve the domain name of the web server into an IP address. It uses the DNS protocol to communicate in the application layer between the client and DNS server.
    2. Telnet客户端在传输层使用TCP协议与Web服务器建立连接。
      The Telnet client uses the TCP protocol in the transport layer to establish a connection with the web server.
    3. Telnet客户端在应用层向Web服务器发送HTTP请求,请求特定的资源。HTTP协议是基于TCP协议的,数据包首先通过HTTP协议传输到传输层,再通过TCP协议传输到网络层
      The Telnet client sends an HTTP request to the web server for a specific resource in the application layer. The data packet is first transmitted through the HTTP protocol to the transport layer and then through the TCP protocol to the network layer.
    4. IP协议会将TCP数据包添加源和目标IP地址,数据包会被封装成数据帧,并且将数据帧传输到网络上。
      The IP protocol adds the source and destination IP addresses to the TCP data packet, which is encapsulated into a data frame and transmitted onto the network.
    5. 数据帧在网络接口层(链路层)会被转换成电子信号,并且通过物理层的电缆、网卡等物理设备传输到Web服务器。
      The data frame is converted into an electronic signal at the network interface layer(Link layer) and transmitted to the web server through physical devices such as cables and network cards in the physical layer.
  • In the web application, what are the primary tasks of a web browser?
    在网络应用中,网络浏览器的主要任务是什么?
    对于网络浏览器,它的主要任务一般有如下三点:

    • 将网址 (URL) 转换为 HTTP 请求;
      Convert web addresses (URL’s) to HTTP requests;
    • 通过 HTTP 与 Web 服务器通信;
      Communicate with web servers via HTTP;
    • 呈现(适当地显示)服务器返回的文档。
      Render (appropriately display) documents returned by a server.
  • In the web application, what are the basic functionalities of a web server?
    在网络应用中,网络服务器的基本功能是什么?

    • 通过TCP接收HTTP请求;
      Receive HTTP request via TCP;
    • 将主机头映射到特定的虚拟主机(共享一个IP地址的许多主机名之一);
      Map Host header to specific virtual host (one of many host names sharing an IP address);
    • 将Request-URI映射到与虚拟主机相关的特定资源上;
      Map Request-URI to specific resource associated with the virtual host
    • 文件:在HTTP响应中返回文件;
      File: Return file in HTTP response
    • 程序: 运行程序并在HTTP响应中返回输出;
      Program: Run program and return output in HTTP response
    • 将资源的类型映射到适当的MIME类型,并使用它来设置HTTP响应中的Content-Type头;
      Map type of resource to appropriate MIME type and use it to set Content-Type header in HTTP response;
    • 记录关于请求和响应的信息。
      Log information about the request and response。
  • In the web application, what are the typical browser-server interactions?
    在网络应用中,经典的浏览器-服务器交互的过程是怎么样的?

    1. 用户在浏览器中输入WEB地址;
      User enters Web address in browser;
    2. 浏览器通过DNS解析出服务器的IP地址;
      Browser uses DNS to locate IP address;
    3. 浏览器与服务器之间开启TCP连接;
      Browser opens TCP connection to server;
    4. 浏览器通过TCP连接向服务器发送HTTP请求;
      Browser sends HTTP request over connection;
    5. 服务器通过TCP连接向浏览器客户端发送HTTP响应;
      Server sends HTTP response to browser over connection;
    6. 浏览器在客户端区域(可视区)展示响应的内容。
      Browser displays body of response in the client area of the browser window。

JavaScript

JavaScript数组排序

JavaScript的数组中的sort()排序方法和C/C++的qsort很像,它的其中一个参数是一个比较函数。

sort()是Array对象的一个方法,对数组的元素进行排序,并返回数组。它的格式为:

sort()  //or
sort(compareFn)

如果没有指明 compareFn ,那么元素会按照转换为的字符串的诸个字符的 Unicode 位点进行排序(省流:逐位字典序)。这是因为JavaScript的函数元素是可以允许不同属性的。

如果指明了 compareFn ,compareFn只接受返回值存在<0、>0或===0的情况。数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:

  • 如果 compareFn(a, b) 大于 0,b 会被排列到 a 之前。
  • 如果 compareFn(a, b) 小于 0,那么 a 会被排列到 b 之前;
  • 如果 compareFn(a, b) 等于 0,a 和 b 的相对位置不变。
  • compareFn(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。

总结:在compareFn函数返回1的时候,它表示b应该排在a的前面,我们输入的时候默认ab前面,因此在sort方法中会交换两个元素的位置当且仅当函数返回1

我们的比较函数可以分成四种情况:数字升序、数字降序、字符串字典序、字符串逆字典序。

数字升序(ascending order)

对于升序我们非常简单,因为我们知道两个数字a,b,a-b>0说明a>b,此时需要调换位置。而a-b≤0,则a≤b此时满足升序不需要替换位置。故可以使用这样的排序函数:

function compareNumbersAscending(a, b)
{ 
    return a - b; 
}

当然这样的写法等价于标准写法:

function compareClassic(a, b)
{ 
    if(a > b)
      return 1;
    else if(a === b)
      return 0;
    else if(a < b)
      return -1;
}

注意:数字的升序不能使用无比较函数的形式!!!因为无比较函数时为逐位字典序比较,不一定等于数字升序。

例如:

function compareNumbers(a, b) { return a - b; }
var A = [80,9,4,66];
console.log("function: " + A.sort(compareNumbers));
console.log("nonfunction: " + A.sort());

此时的function输出为4,9,66,80,是正确的升序。nonfunction的情况输出为4,66,80,9是错误的情况,因为根据逐位字典序,在高一位上8 < 9,故会出现80<9的错误情况。

数字降序(descending order)

有了之前的升序函数的话,我们的降序函数也很容易实现,只需要把a,b参数位置调换即可,于是我们可以这样写:

function compareNumbersDescending(a, b)
{ 
    return compareNumbersAscending(b, a); 
}

当然,我们理解函数的构造后,也可以自己重写:

function compareNumbersDescending(a, b)
{ 
    return b - a; 
}

字符串字典序(alphabetical order)

按照字符串字典序来说,我们不需要比较函数即可实现,因为在没有比较函数的情况下就是字符串字典序排序的。故我们只需要写为A.sort()即可,不需要任何参数。

字符串字典序(alphabetical reverse order)

对于逆字典序,我们除了先用字典序排序后倒序输出外,基本没有什么取巧的办法,按照标准的写法即可。当然此时是逆的,所以当a>b的时候应该输出-1,相反a<b时输出1.

function dec_order(a, b) {
   if (a > b) 
      return -1;
   else if (a < b)
      return 1;
   else return 0;
}

JavaScript对象参数传递

在JavaScript中,如果变量代表一个对象, 那么存储在该变量中的内容就是一个指向该对象的引用(指针),而不是对象本身。这就意味着,我们在赋值和传参的时候,使用的都是引用。

我们通过一个例子加深理解:

var o1 = new Object();
o1.data = "original";
var o2 = new Object();
o2.data = "original";

首先创建两个对象o1,o2,初始值都为original

我们给它们经过一个函数的传参:

objArgs(o1, o2);
function objArgs(param1, param2) {
  // Change the data in param1 and its argument
  param1.data = "changed";
  // Change the object referenced by param2, but not its argument
  param2 = param1;

  window.alert("param1 is " + param1.data + "\n" +
               "param2 is " + param2.data);
  return;
}

在这个函数中,将param1的值改为了changedparam1o1对象的引用,故o1.data = param1.data = "changed"

接下来令param2 = param1;param2的内容为param1的引用。故param2.data = param1.data = "changed"此时在函数中输出为:

因为对象赋值和传参均为引用的特点,在离开函数后重新检查o1,o2的值:

window.alert("o1 is " + o1.data + "\n" +
             "o2 is " + o2.data);

可以得到,我们通过修改param1将o1的值改为了changed。但是param12的值从原来传参的o2的引用变为了param1的引用,相当于两个指针替换了,并没有修改原来o2的值。故输出为:


正则表达式

正则表达式是表示一组字符串的某种方式,可以看成是这一组字符串的集合。

在JavaScript中创建正则表达式有两种方法,一种是使用RegExp()构造函数,另一种是使用正则表达式字面量/ /

例如创建一个包含三个数字的正则表达式,下面两种创建的正则表达式一样:

var acTest1 = new RegExp("^\\d\\d\\d$");
var acTest2= /^\d\d\d$/;

对于正则表达式对象,在JavaScript中有一个test(areaString)方法,它是一个布尔函数,用于检验字符串中是否存在正则匹配内容。下面的例子是如果没检测到则抛出一个报错:

var acTest = new RegExp("^\\d\\d\\d$");
if (!acTest.test(areaCode)) {
  window.alert(areaCode + " is not a valid area code.");
}

对于正则表达式,我们一般使用^作为开头,$作为结尾,或者是以\b开头结尾。其中还有一些非常重要的限定符:

限定符 描述
* 匹配前一个元素 0 次或多次。
+ 匹配前一个元素 1 次或多次。
? 匹配前一个元素 0 次或 1 次。
{n} 匹配前一个元素恰好出现 n 次。
{n,} 匹配前一个元素至少 n 次。
{n,m} 匹配前一个元素至少 n 次,不超过 m 次。

下面是一个正则表达式匹配的例子:

使用一个RegExp实例,编写一个JavaScript函数isValid(),它接受一个String参数,如果该参数与下列电话号码格式之一匹配,就返回true; 否则,就返回false。
(123)456-7890
(123) 456-7890
123/456-7890
123-456-7890
123 456 7890
1234567890

为了节省空间,这里就只讲解如何定义一个通用的正则表达式。

我们发现前三位有可能有括号,也有可能没有,括号是0次或1次的,可以对它使用?限定符。又因为括号是特殊字符,我们还需要通过\转义。

接下来是三个数字,可以通过{}限定符来表示重复。接下来的是一个/或者是空格或者是-或是没有,那么此时使用[]用于匹配指定字符,但别忘记也可能不存在这些字符,还需要使用?限定符。

接下来又是三个数字,继续通过{}限定符来表示重复,和之前的一样,接下来的是一个空格或者是-或是没有,同理使用[]用于匹配指定字符和使用?限定符。

最后就是4个数字结尾,故最后的结果为:

var valid = /^(\(?\d{3}\)?)[ -\/]?\d{3}[- ]?\d{4}$/;

当然这里前面我们也可以分组来做,例如有一组为有括号的,另一组为没有括号的,通过|连起来。例如:

var valid = /^((\(\d{3}\))|\d{3})[ -\/]?\d{3}[- ]?\d{4}$/;

Java Servlet & Session

servlet用于用于客户端与服务器端的交互。

在Web应用程序中,Session是一种服务器端技术(由服务器存储),用于跟踪用户在不同页面和请求之间的状态。Session允许服务器在用户访问网站时创建一个唯一的标识符(session ID),并将该标识符与用户的会话信息相关联。这个会话信息可以包括任何需要在不同页面之间共享的数据,例如用户的登录状态、购物车中的商品、用户的偏好设置等。

我们通过下面的代码来创建或存储session:

HttpSession session = request.getSession();

服务器通过把一个HttpSession对象与服务器维护的每个会话相关联,来支持session。每个对象都会存储其会话的会话ID,还会存储其他与会话相关的信息。

当servlet在其HttpServletRequest 参数上调用getSession()方法,它会有两种情况:

  • 关联的HTTP请求不包含一个有效的session ID时服务器就会创建一个HttpSession对象,并分配一个session ID; getSession()方法会返回最近创建的对象的session ID。
  • 如果HTTP请求包含一个有效的会话ID,那么调用getSession()将会返回以前创建的HttpSession对象,其中包含这个会话ID。

servlet可以通过在HttpSession对象上调用布尔方法isNew(),来确定HttpSession返回的HttpSession对象是否是最新创建的。

更详细的内容已经在之前的页面说明过了,请见:

【WEB】服务器端编程与Java Servlet


CSS

对于CSS中,层叠样式是最重要的内容。在某些时候,在做一个项目过程中你会发现一些应该产生效果的样式没有生效。通常的原因是你创建了两个应用于同一个元素的规则。与层叠密切相关的概念是优先级(specificity),决定在发生冲突的时候应该使用哪条规则。

我们有以下的层叠规则:

  • 当应用两条同级别的规则到一个元素的时候,写在后面的就是实际使用的规则
  • 浏览器是根据优先级来决定当多个规则有不同选择器对应相同的元素的时候需要使用哪个规则。下面的选择器中,优先级递增
    • 通用选择器(*)
    • 类型选择器(例如,h1)和伪元素(例如,::before
    • 类选择器 (例如,.example),属性选择器(例如,[type="radio"])和伪类(例如,:hover
    • ID 选择器(例如,#example)。
    • 内联样式(例如添加到HTML<span>属性中的style="font-weight:bold"
  • 一些设置在父元素上的 CSS 属性是可以被子元素继承。当元素的一个继承属性(inherited property)没有指定值时,则取父元素的同属性的计算值。

我们可以通过一个简单的例子来理解这个层叠规则,对于下面这两条CSS声明:

background-color: silver;
font-size: larger;

这两个声明将被分别称为“背景声明”和“文本声明”。

  • (a)编写CSS样式规则,将背景声明应用于div元素,并将文本声明应用于strong元素。
  • (b)编写单个样式规则,同时将背景声明和文本声明应用于p元素和em元素。
  • (c)编写单个样式规则,将背景声明应用于id属性值为Nevada的HTML元素以及属于shiny类的元素
  • (d)编写一个样式规则,将文本声明应用于属于bigger类的span元素
  • (e)编写一个样式规则,将文本声明应用于属于其他span元素后代的span元素。
  • (f)编写一个样式规则,当光标悬停在超链接上时应用背景声明。

对于第一个问题,它非常简单,只需要给div元素和strong元素,分别赋予声明即可:

div { background-color: silver }
strong { font-size: larger }

第二个问题,编写单个样式规则同时应用两个元素,两个元素之间应该使用逗号隔开。

p, em { background-color: silver; font-size: larger }

第三个问题,编写单个样式规则,将背景声明应用于一个id上和一个类上的所有元素。我们一般用#来声明id,用.来声明一个类:

#Nevada, .shiny { background-color: silver }

第四个问题,应用在类之下的元素,我们一般用元素.类.类 元素来声明:

span.bigger { font-size: larger }
.bigger span{ font-size: larger }

第五个问题,涉及继承,我们一般用父元素 子元素来声明:

span span { font-size: larger }

第六个问题,对于锚元素(a)的一些属性,:hover它是伪类选择器,一般写作a:伪类

a:hover { background-color: silver }

DOM技术

用于客户端与浏览器的交互,一般用于对用户动作做出反馈的情况,例如鼠标移动之类的,常见的有:

在使用内部事件属性之前,必须在文档的head中包含一个meta元素,用于为文档内的脚本指定默认的语言;content的内容为"text/javascript"告诉浏览器用JavaScript编写内部事件属性。

<meta http-equiv="Content-Script-Type" content="text/javascript" />

我们在html中设置内部事务属性,并在JavaScript中定义函数用于交互,具体例子请见:

【WEB】浏览器和文本对象模型(DOM)

这里的一切都有始有终,却能容纳所有的不期而遇和久别重逢。
最后更新于 2023-05-23