Web阶段性技术文档(Cookie)

 

一、基本概念的学习

1、什么是Cookie

Cookie 是服务器保存在浏览器的一小段文本信息。浏览器每次向服务器发出请求,就会自动附上这段信息。

Cookie 就是这么简单,这就是 Web 开发里 Cookie 的含义。

 

2、Cookie的作用

(1)Cookie 主要用来分辨两个请求是否来自同一个浏览器

 

(2)用来保存一些状态信息,例如:

a.对话(session)管理:保存登录、购物车等需要记录的信息。

b.个性化:保存用户的偏好,比如网页的字体大小、背景色等等。

c.追踪:记录和分析用户行为

不推荐使用Cookie作为客户端存储,原因:

a.它的容量很小(4KB)。

b.缺乏数据操作接口。

c.而且会影响性能。

客户端储存应该使用 Web storage API IndexedDB

 

(3)使用Cookie一般有两个作用

第一个作用是识别用户身份

比如用户A用浏览器访问了http://a.com,那么http://a.com的服务器就会立刻给 A 返回一段数据「uid=1」(这就是Cookie)。当 A 再次访问http://a.com的其他页面时,就会附带上「uid=1」这段数据。

同理,用户 B 用浏览器访问 http://a.com 时,http://a.com 发现 B 没有附带 uid 数据,就给B分配了一个新的 uid,为2,然后返回给B一段数据「uid=2」。B之后访问http://a.com的时候,就会一直带上「uid=2」这段数据。

借此,http://a.com的服务器就能区分A和B两个用户了。

 

第二个作用是记录历史

假设 http://a.com是一个购物网站,当A在上面将商品A1、A2加入购物车时JS可以改写Cookie,改为「uid=1;cart=A1,A2」,表示购物车里有A1和A2两样商品了。这样一来,当用户关闭网页,过三天再打开网页的时候,依然可以看到A1、A2躺在购物车里,因为浏览器并不会无缘无故地删除这个Cookie。

借此达到里记录用户操作历史的目的。

 

3、Cookie的组成

Cookie 包含以下几方面的信息:

a. Cookie 的名字

b. Cookie 的值。(真正的数据写在这里面)(a、b两点就是键值对 )

c. 到期时间。

d. 所属域名。(默认是当前域名)

e. 生效的路径。(默认是当前网址)(c/d/e是cookie的属性)

 

4、Cookie的作用过程

举例来说:

假设用户访问网址www.example.com,服务器在浏览器写入一个 Cookie。这个 Cookie

就会包含www.example.com这个域名(d),以及根路径/(e)。这意味着,这个 Cookie 对该域名的根路径和它的所有子路径都有效。如果路径设为/forums,那么这个 Cookie 只有在访问www.example.com/forums及其子路径时才有效。

以后,浏览器一旦访问这个路径,浏览器就会附上这段 Cookie 发送给服务器

 

5、Cookies作用范围

浏览器的同源政策规定,两个网址只要域名相同端口相同,就可以共享 Cookie。注意,这里不要求协议相同。也就是说,http://example.com设置的 Cookie,可以被https://example.com读取。

同源限制方面内容可以参考网页:

https://wangdoc.com/javascript/bom/same-origin.html

 

二、HTTP 协议中的Cookie

1、HTTP 回应:Cookie 的生成(服务器端生成cookies)

服务器如果希望在浏览器保存 Cookie,就要在 HTTP 回应的头信息里面,放置一个Set-Cookie字段:

Set-Cookie:foo=bar

上面的代码会在浏览器保存一个名为foo的 Cookie,它的值为bar。

设置的格式为:<键(名)>=<值>。

 

HTTP 回应可以包含多个Set-Cookie字段,即在浏览器生成多个 Cookie。下面是一个例子:

HTTP/1.0 200 OK

Content-type: text/html

Set-Cookie: yummy_cookie=choco

Set-Cookie: tasty_cookie=strawberry

[page content]

 

除了 Cookie 的值,Set-Cookie字段还可以附加 Cookie 的属性。一个Set-Cookie字段里面,可以同时包括多个属性没有次序的要求。下面是设置一个Cookie的例子:除了名与它的值,还包含Domain属性Secure属性和HttpPnly属性:

Set-Cookie:<cookie-name>=<cookie-value>;

Domain=<domain-value>;Secure; HttpOnly

 

除了键=值来设置cookie的名字和值之外,还可以设置属性。

a. Expires,Max-Age用来设置cookie持续时间。

b. Domain,Path设置发送http请求时那些域名和路径需要附带这个Cookie。

c. Secure属性指定浏览器只有在加密协议 HTTPS 下才能发送。

d. HttpOnly属性指定该 Cookie 无法通过 JavaScript 脚本拿到。

具体用法可以参考网上的很多博客,这里不再赘述。

 

2、HTTP 请求:Cookie 的发送(浏览器发送Cookie)

浏览器向服务器发送 HTTP 请求时,每个请求都会带上相应的 Cookie。也就是说,把服务器早前保存在浏览器的这段信息,再发回服务器。这时要使用 HTTP 头信息的Cookie字段。

Cookie: foo=bar

上面代码会向服务器发送名为foo的 Cookie,值为bar。

 

Cookie字段可以包含多个 Cookie,使用分号(;)分隔。

Cookie: name=value; name2=value2; name3=value3

 

下面是一个Http请求的例子

GET /sample_page.html HTTP/1.1

Host: www.example.org

Cookie: yummy_cookie=choco; tasty_cookie=strawberry

 

服务器收到浏览器发来的 Cookie 时,有两点是无法知道的(因为这些Cookie的属性只保存在浏览器上)。

a.Cookie 的各种属性,比如何时过期。

b.哪个域名设置的 Cookie,到底是一级域名设的,还是某一个二级域名设的。

 

三、document.cookie读写当前网页的Cookie

1、读Cookie

读取的时候,它会返回当前网页的所有 Cookie,前提是该 Cookie 不能有HTTPOnly属性。

document.cookie // "foo=bar;baz=bar"

 

2、写Coookie

document.cookie属性是可写的,可以通过它为当前网站添加 Cookie。等号两边不能有空格

document.cookie = 'fontSize=14';

但是,document.cookie一次只能写入一个 Cookie,而且写入并不是覆盖,而是添加

document.cookie = 'test1=hello';

document.cookie = 'test2=world';

document.cookie

// test1=hello;test2=world

 

写入 Cookie 的时候,可以一起写入 Cookie 的属性。

document.cookie = "foo=bar; expires=Fri, 31 Dec 2020 23:59:59 GMT";

各个属性的写入注意点如下:

a. path属性必须为绝对路径,默认为当前路径。

b. domain属性值必须是当前发送 Cookie 的域名的一部分。比如,当前域名是example.com,就不能将其设为foo.com。该属性默认为当前的一级域名(不含二级域名)。

c. max-age属性的值为秒数。

d. expires属性的值为 UTC 格式,可以使用 Date.prototype.toUTCString ()进行日期格式转换。

document. cookie写入 Cookie 的例子如下。

Document.cookie = 'fontSize=14; '

         + 'expires=' + someDate.toGMTString() + '; '

 + 'path=/subdirectory; '

 + 'domain=*.example.com';

Cookie 的属性一旦设置完成,就没有办法读取这些属性的值

 

3、Cookie 的删除

删除一个现存 Cookie 的唯一方法,是设置它的expires属性为一个过去的日期

document.cookie = 'fontSize=;expires=Thu, 01-Jan-1970 00:00:01 GMT';

上面代码中,名为fontSize的 Cookie 的值为空,过期时间设为1970年1月1月零点,就等同于删除了这个 Cookie。

 

四、以登录注册理解Cookie的作用过程

1、Cookie在注册登录时的作用过程

注册:注册时把账号密码写入数据库。

登录:第一次登录时服务器给浏览器发送Cookie。

后台的登录路由代码(nodejs):

else if (path === '/sign_in' && method === 'POST') {

        readBody(request).then((body) => {

            let strings=body.split('&')

            let hash = {}

            strings.forEach((string) => {

                let parts = string.split('=')

                let key = parts[0]

                let value = parts[1]

                hash[key] = decodeURIComponent(value)

            })

            let {

                email,

                password

            } = hash

            var users = fs.readFileSync('./db/users', 'utf8')

            try {

                users = JSON.parse(users) // []

            } catch (exception) {

                users = []

            }

            let found

            for (let i = 0; i < users.length; i++) {

                if (users[i].email === email && users[i].password === password) {

                    found = true

                    break

                }

            }

            if (found) {//关键在这里,验证成功,设置登录Cookie为登录的邮箱,并放在响应里发给浏览器

                response.setHeader('Set-Cookie', `sign_in_email=${email}`)

                response.statusCode = 200

            } else {

                response.statusCode = 401

            }

            response.end()

        })

}

在登录成功的一瞬间,需要后台设置一个Cookie,记录一下登陆的用户id(这里用邮箱表示,代码在上面),然后发响应给浏览器

例如在服务器端设置响应头:set-cookies:user_email=1@mtt.com

这时候我们查看响应:

发现响应头已经设置cookie:

然后跳转到主页,这时候我们查看跳转到主页的请求:

 

发现跳转到主页的请求头中包含cookie字段(以后访问这个域名都会带着这个Cookie)!所以,就像上文所说的:

如果服务器给了浏览器一个setcookie的响应头,那么这个浏览器以后所有的请求,只要是相同的源(即就是上次给我发送Cookie的那个域名,域名和端口相同),那就么就会把当时服务器发给这个浏览器的Cookie带着。

以后,浏览器一旦访问这个路径,浏览器就会附上这段 Cookie 发送给服务器

即:第一次请求,服务器为浏览器设置Cookie.下次请求,浏览器带上Cookie,发送给服务器。

第一次登录的时候,服务器给浏览器的响应设置一个Cookie,set-cookies:user_email=1@mtt.com,然后当浏览器下次进行请求的时候,发现Cookie中有名为User_email的Cookie,而且我发送请求的域名还是上次发给我带Cookie的响应的那个域名。那么就无需再次登录了。

相当于服务器给浏览器发了进入门票,下次或下下次浏览器在进入服务器的时候给服务器看票就可以了。

 

2、后台读取Cookie保留登录状态与删除Cookie退出登录状态

首页代码:

<body>

    <h1>我是首页</h1>

    <div class="">

        <a href="./sign_up">注册</a>

        <a href="./sign_in">登录</a>

    </div>

   

    <h1>你的状态是:__status__</h1>

    <h1>你的邮箱账号是:__email__</h1>

    <h1>你的密码是:__password__</h1>

 

    <a href="javascript:;" id="logOffBtn">退出登录(删除cookie)</a>

 

</body>

<script>

logOffBtn.addEventListener("click", () => {

        // 删除一个现存 Cookie 的唯一方法,是设置它的expires属性为一个过去的日期。

        document.cookie = 'sign_in_email=;expires=Thu, 01-Jan-1970 00:00:01 GMT'

        window.location = "/"

    })

</script>

 

后台路由代码:

if (path === '/') {

        response.statusCode = 200

        let string = fs.readFileSync('./index.html')

        string = string.toString();

        var users = fs.readFileSync('./db/users', 'utf8')

        users = JSON.parse(users)//转化为user对象数组

 

        console.log(users);

        let cookies = request.headers.cookie || ''//['email=111', 'asdasd=111']

        cookies = cookies.split("; ")

        let hash={}

 

        cookies.forEach((string)=>{

            let parts = string.split("=")

            let key = parts[0]

            let value = parts[1]

            hash[key] = value;

        })

       

        let eamil = hash.sign_in_email

        let foundedUser

        users.forEach((userObj)=>{

            if(userObj.email===eamil){

                foundedUser = userObj;

            }

        }

)

        console.log(foundedUser);

 

        if(foundedUser){

            string = string.replace('__status__', '已登录')

            string = string.replace('__email__', foundedUser.email)

            string = string.replace('__password__', foundedUser.password)

        }else{

            string = string.replace('__status__', '未登录,请去登录')

            string = string.replace('__email__', '没')

            string = string.replace('__password__', '没')

        }

       

        response.setHeader('Content-Type', 'text/html;charset=utf-8')

        response.write(string)

        response.end()

    }

 

在没有Cookie的时候,首页的状态:

 

登录之后,后台根据Cookie查询数据库,将用户名与密码传到前台的首页上:

退出登录将删除Cookie并刷新页面,重新回到未登录的状态

 

3、Cookie在登录的时候的特点

a. 第一次登录的时候,服务器通过 Set-Cookie 响应头设置 Cookie,然后以响应的形式发给浏览器

b. 浏览器得到 响应中Cookie 之后,之后每次请求这个域名都要带上这个 Cookie

c. 之后服务器读取当时自己设置的 Cookie 就知道登录用户的信息(email)

 

4、几个关于Cookie的问题

a.我在Chrome登录了得到Cookie,用Safari访问,Safari会带上Cookie吗?    回答:不会。

b.Cookie存在哪?

回答:Windows 存在 C 盘的一个文件里。

c.Cookie会被用户篡改吗?

回答:可以,例如在谷歌浏览器开发者模式下的application->Cookie中可以手动修改,修改之后,下次发送请求时,附带的就是修改后的Cookie。

JS中也有可以操作cookie的api( 假如换成别的用户的账号,那么还可以登录成功的话,就会存在风险问题.Session 来解决这个问题,防止用户篡改)。

后端可以强制设置不允许修改Cookie,只要将Cookie的属性设置为Httponly即可(还可以手动改,但是JS改不了,也无法获取),具体语法看 MDN。

d.Cookie 有有效期吗?

回答:默认有效期20分钟左右,不同浏览器策略不同(如果浏览器一直开着,那么Cookie不会被删除.如果关闭浏览器,那么浏览器为了安全考虑,20分钟左右后可能会删除Cookie.这也取决于服务器如何设置Cookie的有效期)。

后端可以强制设置有效期,具体语法看 MDN。

e.Cookie 也有同源策略吗?

回答:也有,不过跟 AJAX 的同源策略稍微有些不同。

当请求 qq.com 下的资源时,浏览器会默认带上 qq.com 对应的 Cookie,不会带上 baidu.com 对应的 Cookie当请求 v.qq.com 下的资源时,浏览器不仅会带上v.qq.com的Cookie,还会带上 qq.com 的 Cookie。另外 Cookie 还可以根据路径做限制,但这个功能用得比较少。

 

5、需要注意的细节问题

a.为什么前后端都要进行表单验证?

前后端都要验证邮箱格式是否正确,账号密码格式是否正确,两次提交的密码是否相同等。因为黑客可以绕过前端的js验证流程,例如黑客可以直接使用curl 进行请求的发送,直接与后台服务器进行交互。所以后台也需要进行表单验证。

 

b.Cookie如何手动关闭?

 

五、项目说明

1、这个项目是一个cookie的简单例子, 有以下结构:

index.html: 首页

sign_in.html: 登录页面

sign_up.html: 注册页面

server.js: 服务器

db/users: 模拟数据库, 实质上是一个数组, 每个数组项是一个对象, 表示一个用户。

 

2、程序运行需要使用node作为服务器

node server.js 8888

在浏览器中localhost:8888, 就可以看到index.html页面。

 

3、 在地址栏输入localhost:8888/sign_up, 会进入注册页面, 即sign_up.html。

输入要注册的邮箱即密码, 若已注册过则显示已注册, 没有注册则会注册成功。

在地址栏输入localhost:8888/sign_in, 得到登录页面sign_in.html, 输入刚才注册的账号, 会进入首页index.html, 还会显示个人账户信息。

当输入localhost:8888直接进入index.html页面时, 没有用户登录. 此时就没有设置cookie, 首页不会显示用户的cookie。

若通过用户登录进入首页, 则会设置cookie. 首页也会显示账户.

 

 

server.js:

var http = require('http')

var fs = require('fs')

var url = require('url')

var port = process.argv[2]

var sessions ={}

if (!port) {

    console.log('?\nnode server.js 8888 ')

    process.exit(1)

}

 

var server = http.createServer(function (request, response) {

    var parsedUrl = url.parse(request.url, true)

    var pathWithQuery = request.url

    var queryString = ''

    if (pathWithQuery.indexOf('?') >= 0) {

        queryString = pathWithQuery.substring(pathWithQuery.indexOf('?'))

    }

    var path = parsedUrl.pathname

    var query = parsedUrl.query

    var method = request.method

 

    

    //   这里开始写注册登录的路由

 

    console.log('含查询字符串的路径\n' + pathWithQuery)

 

    if (path === '/') {

        response.statusCode = 200

        let string = fs.readFileSync('./index.html')

        string = string.toString();

        var users = fs.readFileSync('./db/users', 'utf8')

        users = JSON.parse(users)//转化为user对象数组

 

        console.log(users);//打印在服务器端的控制台

        let cookies = request.headers.cookie || ''//'sessionID=xxx', 'asdasd=111'

        console.log("cookies:"+cookies);

        cookies = cookies.split("; ")

        let hash={}

        cookies.forEach((string)=>{

            let parts = string.split("=")

            let key = parts[0]

            let value = parts[1]

            hash[key] = value;

        })

      

        let eamil 

        let mySession = sessions[hash.sessionID];

 

        if(mySession){

            console.log("mySession.sign_in_email:::"+mySession.sign_in_email)

            eamil = sessions[hash.sessionID].sign_in_email

        }

        let foundedUser

        users.forEach((userObj)=>{

            if(userObj.email===eamil){

                foundedUser = userObj;

            }

        })

        console.log("foundedUser"+foundedUser);

        if(foundedUser){

            string = string.replace('__status__', '已登录')

            string = string.replace('__email__', foundedUser.email)

            string = string.replace('__password__', foundedUser.password)

        }else{

            string = string.replace('__status__', '未登录,请去登录')

            string = string.replace('__email__', '没')

            string = string.replace('__password__', '没')

        }

        

        response.setHeader('Content-Type', 'text/html;charset=utf-8')

        response.write(string)

        response.end()

    } else if (path === '/sign_up' && method === 'GET') { //这个路由只限进入sign_up这个页面,所以只需要用get,不附带数据,下面提交表单采用post

        response.statusCode = 200

        let string = fs.readFileSync('./sign_up.html')

        response.setHeader('Content-Type', 'text/html;charset=utf-8')

        response.write(string)

        response.end()

    } else if (path === '/sign_up' && method === 'POST') { //提交注册表单的路由

        readBody(request).then((body) => { //使用封装的读取body的函数,成功后参数为body,因为这里是异步事件,所以需要使用promise封装

            let message = body.split('&') //['email=1','password=2','repassword=3']

            let hash = {}

            message.forEach(element => {

                let parts = element.split('=')

                let key = parts[0]

                let value = parts[1]

                hash[key] = decodeURIComponent(value)

            });

            console.log(hash);

            let {

                email,

                password,

                repassword

            } = hash //es6语法

            if (email.indexOf('@') === -1) { //邮箱中没有@,返回一个邮箱无效的错误json

                response.statusCode = 400

                response.setHeader('Content-Type', 'application/json;charset=utf-8')

                response.write(`{

                        "email":"invalid"

                }`)

            } else { //存入db中的users数据库

                let users = fs.readFileSync('./db/users', 'utf8')

                console.log(users)

                console.log(typeof users)

                try {

                    users = JSON.parse(users) // []

                    console.log(typeof users)

                } catch (exception) {

                    users = []

                }

                let inUse = false

                for (let i = 0; i < users.length; i++) {

                    let user = users[i]

                    if (user.email === email) {

                        inUse = true

                        break;

                    }

                }

                if (inUse) {

                    response.statusCode = 400

                    response.write('email in use')

                } else {

                    users.push({

                        email: email,

                        password: password

                    })

                    let usersString = JSON.stringify(users)

                    fs.writeFileSync('./db/users', usersString)

                    response.statusCode = 200

                }

            }

            response.end()

        })

    } 

    /*接下来是登录的两个路由*/ 

    else if (path === '/sign_in' && method === 'GET') {//同样GET是获取登录页面,POST是表单提交

        let string = fs.readFileSync('./sign_in.html', 'utf8')

        response.statusCode = 200

        response.setHeader('Content-Type', 'text/html;charset=utf-8')

        response.write(string)

        response.end()

 

    } else if (path === '/sign_in' && method === 'POST') {

        readBody(request).then((body) => {

            let strings = body.split('&') // ['email=1', 'password=2', 'password_confirmation=3']

            let hash = {}

            strings.forEach((string) => {

 

                // string == 'email=1'

                let parts = string.split('=') // ['email', '1']

                let key = parts[0]

                let value = parts[1]

                hash[key] = decodeURIComponent(value) // hash['email'] = '1'

 

         

 

   })

            let {

                email,

                password

            } = hash

            var users = fs.readFileSync('./db/users', 'utf8')

            try {

                users = JSON.parse(users) // []

            } catch (exception) {

                users = []

            }

 

            let found

            for (let i = 0; i < users.length; i++) {

                if (users[i].email === email && users[i].password === password) {

                    found = true;//搜索数据库成功,那么把这个user对象的全部信息赋值给found

                    break

                }

            }

            if (found) {//验证成功,设置登录Cookie为登录的邮箱,并放在响应里发给浏览器

                let sessionID = (Math.random())*100000

                sessions[sessionID] = {sign_in_email:`${email}`}

                console.log("登录时填进去的sessions的id为:"+sessionID)

                console.log("登录时填进去的sessions的email:"+sessions[sessionID].sign_in_email)

                response.setHeader('Set-Cookie', `sessionID=${sessionID}`)

                response.statusCode = 200

            } else {

                response.statusCode = 401

            }

            response.end()

        })

    } else {

        response.statusCode = 404

        response.setHeader('Content-Type', 'application/json;charset=utf-8')

        response.write(`{

      "error":"404error"

    }`)

        response.end()

    }

})

 

 

 

 

server.listen(port)

console.log('监听 ' + port + ' 成功\n打开 http://localhost:' + port)

 

function readBody(request) { //封装读取请求体的函数

    return new Promise((resolve, reject) => {

        let body = [] //由于http接受数据是一小块一小块接受的,所以我们写代码也需要一块一块的接收,然后拼接在一起

        request.on('data', (chunk) => {

                body.push(chunk)

            })

            .on('end', () => {

                body = Buffer.concat(body).toString();

                resolve(body)

            })

    })

}

index.html:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>首页</title>

</head>

<body>

    <h1>欢迎 __user__ 登录</h1>

</body>

</html>

sign_in.html:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>登录</title>

    <style>

        * {

            margin: 0;

            padding: 0;

        }

        body {

            border: 1px solid red;

            min-height: 100vh;

            display: flex;

            justify-content: center;

            align-items: center;

            flex-direction: column;

        }

        .form-wrapper {

            border: 1px solid #ddd;

            padding: 20px;

            min-width: 350px;

        }

        .form-wrapper .row{

            margin: 10px 0;

        }

        .form-wrapper .row>label {

            display: inline-block;

            min-width: 4em;

        }

    </style>

</head>

<body>

    <div class="form-wrapper">

        <h1>登录</h1>

        <form action="" id="signInForm">

            <div class="row">

                <label for="">邮箱</label>

                <input type="text" name="email">

                <span class="message"></span>

            </div>

            <div class="row">

                <label for="">密码</label>

                <input type="password" name="password">

                <span class="message"></span>

            </div>

            <div class="row">

                <input type="submit" value="登录">

            </div>

        </form>

    </div>

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>

    <script>  

        $form = $('#signInForm')

        $form.on('submit', (e)=>{

            e.preventDefault()

            let hash = {}

            let need = ['email', 'password']

            need.forEach((name)=>{

                let value = $form.find(`[name=${name}]`).val()

                hash[name] = value

            })

            $form.find('.message').each((index, span)=>{

                $(span).text('')

            })

            if(hash['email'] === '') {

                $form.find('[name="email"]').siblings('.message').text("请填写邮箱")

                return 

            }

            if(hash['password'] === '') {

             $form.find('[name="password"]').siblings('.message').text("请填写密码")

                return 

            }

            $.post('/sign_in', hash)

            .then((response)=>{

                window.location.href='/'

            }, ()=>{

                alert('邮箱或密码错误')

            })

        })

    </script>

</body>

</html>

sign_up.html:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>注册</title>

    <style>

        * {

            margin: 0;

            padding: 0;

        }

        body {

            border: 1px solid red;

            min-height: 100vh;

            display: flex;

            justify-content: center;

            align-items: center;

            flex-direction: column;

        }

        .form-wrapper {

            border: 1px solid #ddd;

            padding: 20px;

            min-width: 350px;

        }

        .form-wrapper .row{

            margin: 10px 0;

        }

        .form-wrapper .row>label {

            display: inline-block;

            min-width: 4em;

        }

    </style>

</head>

<body>

    <div class="form-wrapper">

        <h1>注册</h1>

        <form action="" id="signUpForm">

            <div class="row">

                <label for="">邮箱</label>

                <input type="text" name="email">

                <span class="message"></span>

            </div>

            <div class="row">

                <label for="">密码</label>

                <input type="password" name="password">

                <span class="message"></span>

            </div>

            <div class="row">

                <label for="">确认密码</label>

                <input type="password" name="password_confirmation">

                <span class="message"></span>

            </div>

            <div class="row">

                <input type="submit" value="注册">

            </div>

        </form>

    </div>

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>

    <script>

        

        $form = $('#signUpForm')

        $form.on('submit', (e)=>{

            e.preventDefault()

            let hash = {}

            let need = ['email', 'password', 'password_confirmation']

            need.forEach((name)=>{

                let value = $form.find(`[name=${name}]`).val()

                hash[name] = value

            })

            $form.find('.message').each((index, span)=>{

                $(span).text('')

            })

            if(hash['email'] === '') {

                $form.find('[name="email"]').siblings('.message').text("请填写邮箱")

                return 

            }

            if(hash['password'] === '') {

                $form.find('[name="password"]').siblings('.message').text("请填写密码")

                return 

            }

            if(hash['password_confirmation'] === '') {

                $form.find('[name="password_confirmation"]').siblings('.message').text("请填写密码")

                return 

            }

            if(hash["password"] !== hash['password_confirmation']) {

                $form.find('[name="password_confirmation"]').siblings('.message').text("密码不匹配")

                return 

            }

            $.post('/sign_up', hash)

            .then((response)=>{

                let message = response

                console.log(message)

               if (message.email && message.email === 'successed') {

                    $form.find('[name="email"]').siblings('.message')

                        .text('注册成功')

                }

            }, (xhr)=>{

                console.log(xhr)

                //服务器端设置了application/json头

                let {message}=xhr.responseJSON

                console.log(message)

                if (message.email && message.email === 'invalid') {

                    $form.find('[name="email"]').siblings('.message')

                        .text('邮箱格式错误')

                } else if (message.email && message.email === 'used') {

                    $form.find('[name="email"]').siblings('.message')

                        .text('邮箱已被注册')

                }

            })

        })

    </script>

</body>

</html>

六、参考资料

1、网页注册登录功能的实现以及Cookie的利用

https://www.jianshu.com/p/58760ef27acd

2、使用cookie做用户登录的过程详解

https://blog.csdn.net/looksunli/article/details/9799395

3、深入理解Cookie

https://www.jianshu.com/p/6fc9cea6daa2

4、Cookie-大道至简

https://blog.csdn.net/ssspk_/article/details/92611751

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值