728x90

https://velog.io/@pkbird/Nunjucks-basic

 

팔로우하기

팔로우끊기

 

버튼교체!!!!

 

해결함 

넌적스 제대로 안됐던 이유는 club.html코드보면서 라우터 mypage.js 걸로 왜 안되냐 하고 있었던 것~~

 

 (mypage에서 팔로우 정보 불러올때 썼던 것처럼)

 

club.html에서 쓸

followerIdList를 club.js에서 쓸거라고 넣어줘야 됐음

 


목표:

(나자신)   - 아무것도 안뜨게

(팔로잉한 사람followerIdlist에 포함되어있음)  - 팔로우끊기

(팔로우 안함사람) – 팔로우하기

 

///넌적스 if절은//

만약에 트윗유저가 followerIdlist에 포함되어있지 않고 나자신이 아니면

팔로우하기

그게 아니면(트윗유저가 followerIdlist에 포함되어있으면 그리고 나자신 아니면)

팔로우끊기

 


 

 

 

 

(좋아요는 아직 기능안해서 주석처리)

 

club.html

{% extends "layout.html" %} {% block css %}
<link rel="stylesheet" href="/club/stylesheets/club.css" />
{% endblock %} {% block content %}
<div class="search_field">
  <div class="fake_field">
    <input
      class="picture-search"
      type="text"
      name="search"
      placeholder="사진 검색"
    />
    <button class="picture-btn btn">검색</button>
  </div>
</div>

<div class="feed-container">
  <h3>인기 피드</h3>

  <!-- <form id="myFeed">
    <button id="feed-btn" type="submit" class="black btn">
      <a class="picture-uploads" href="/clubupload">업로드</a>
    </button>
    {% for twit in twits %}
    <tr class="clubMain">
      <td>
        <a href="/">
          <img style="width: 100px" src="{{twit.img}}" alt="섬네일"/>
        </a>
      </td>
    </tr>
    {% endfor %}
  </form> -->
  {% if user and user.id %}
  <button id="feed-btn" type="submit" class="black btn">
    <a class="picture-uploads" href="/clubupload">업로드</a>
  </button>
  {% endif %} {% for twit in twits %}
  <div class="twit">
    <input type="hidden" value="{{twit.User.id}}" class="twit-user-id" />
    <input type="hidden" value="{{twit.id}}" class="twit-id" />
    <div class="twit-author">{{twit.User.nick}}</div>

    {% if not followerIdList.includes(twit.User.id) and twit.User.id !== user.id
    %}
    <button class="twit-follow btn">팔로우하기</button>
    {% elif twit.User.id !== user.id%}
    <button class="twit-unfollow btn">팔로우끊기</button>
    {% endif %}

    <div class="twit-img">
      <a href="/clubdetail/:id"
        ><img style="width: 100px" src="{{twit.img}}" alt="섬네일"
      /></a>
    </div>

    <button class="like btn">좋아요</button>

    <button class="unlike btn">좋아요 취소</button>

    <div class="twit-content"></div>
  </div>
  {% endfor %}
</div>
{% endblock %} {% block script %}
<script>
  //팔로우
  document.querySelectorAll(".twit-follow").forEach(function (tag) {
    console.log("팔로이있는창");
    tag.addEventListener("click", function () {
      console.log("팔로우클릭");
      const myId = document.querySelector("#my-id");
      if (myId) {
        console.log("myid가져와지니?");
        const userId = tag.parentNode.querySelector(".twit-user-id").value;
        console.log(userId);
        //if (userId !== myId.value)원래 이거였음 근데 바꿔도 콘솔에는 찍히네

        if (userId !== myId.value) {
          if (confirm("팔로잉하시겠습니까?")) {
            console.log("팔로요청되나?");
            axios
              .post(`/user/${userId}/follow`)
              .then(() => {
                console.log("팔로됐나");
                location.reload();
              })
              .catch((err) => {
                console.log("에러");
                console.error(nperr);
              });
          }
        }
      }
    });
  });
  //팔로우끊기
  document.querySelectorAll(".twit-unfollow").forEach(function (tag) {
    tag.addEventListener("click", function () {
      const myId = document.querySelector("#my-id");
      console.log(myId);
      if (myId) {
        const userId = tag.parentNode.querySelector(".twit-user-id").value;

        if (userId !== myId.value) {
          if (confirm("팔로잉끊으시겠습니까?")) {
            console.log("팔로요청되나?");
            axios
              .post(`/user/${userId}/unfollow`)
              .then(() => {
                console.log("팔로됐나");
                location.reload();
              })
              .catch((err) => {
                console.log("에러");
                console.error(err);
              });
          }
        }
      }
    });
  });

  //   forEach.call(document.querySelectorAll(".like"), function (tag) {
  //   tag.addEventListener("click", function () {
  //     var isLoggedIn = document.querySelector("#my-id");
  //     var twitId = tag.parentNode.querySelector("#twit-id").value;
  //     if (idLoggedIn) {
  //       var xhr = new XMLHttpRequest();
  //       xhr.onload = function () {
  //         if (xhr.status === 200) {
  //           location.reload();
  //         } else {
  //           console.error(xhr.responseText);
  //         }
  //       };
  //       xhr.open("POST", "/club/" + twitId + "/like");
  //       xhr.send();
  //     }
  //   });
  // });
  // forEach.call(document.querySelectorAll(".unlike"), function (tag) {
  //   tag.addEventListener("click", function () {
  //     var isLoggedIn = document.querySelector("#my-id");
  //     var twitId = tag.parentNode.querySelector("#twit-id").value;
  //     if (idLoggedIn) {
  //       var xhr = new XMLHttpRequest();
  //       xhr.onload = function () {
  //         if (xhr.status === 200) {
  //           location.reload();
  //         } else {
  //           console.error(xhr.responseText);
  //         }
  //       };
  //       xhr.open("DELETE", "/club/" + twitId + "/like");
  //       xhr.send();
  //     }
  //   });
  // });
</script>

{% endblock %}

 location.reload(); //이거 새로고침!

<button class="twit-unfollow btn">팔로우끊기</button//띄어쓰기하면 클래스 하나 더 들어가는거

 

 

팔로잉한 데이터 가져오려면

라우터에서 만들어줘야했음!

 

 

경로는 라우터에서

get으로 club.html불러주고

use로 사용하겠다.

어떻게 사용할지~

 

club.js

const express = require("express");
const { isLoggedIn, isNotLoggedIn } = require("../middlewares");
const { Club, User } = require("../../models");
const router = express.Router();

router.use((req, res, next) => {
  res.locals.user = req.user;
  // res.locals.followerCount = 0;
  // res.locals.followingCount = 0;
  // res.locals.followerIdList = [];
  res.locals.followerCount = req.user ? req.user.Followers.length : 0;
  res.locals.followingCount = req.user ? req.user.Followings.length : 0;
  res.locals.followerIdList = req.user
    ? req.user.Followings.map((f) => f.id)
    : [];
  next();
});


router.get("/", async (req, res, next) => {
  try {
    const clubs = await Club.findAll({
      include: {
        model: User,
        attribute: ["id", "nick"],
      },
      order: [["createdAt", "DESC"]],
    });
    res.render("club/club", {
      title: "mountain feed",
      twits: clubs,
    });
  } catch (error) {
    console.error(error);
    next(error);
  }
});

module.exports = router;

참고로 라우트 쓸려면

 

app.js

에 라우트 선언해야함

const clubRouter = require("./routes/club/club");

미들웨어도 추가

app.use("/club"clubRouter);

 

 

 

 

결과물~!!

마이페이지~

 

 

 

 

 

https://design-system.service.gov.uk/components/tabs/

 

Tabs – GOV.UK Design System

Components Tabs Experimental This component is currently experimental because more research is needed to validate it. The tabs component lets users navigate between related sections of content, displaying one section at a time. Contents Past day Past week

design-system.service.gov.uk

이건 넌적스 유용하게 쓸 수 있을 거 같은 사이트

728x90
728x90

몽고디비

몽구스

스키마

 

몽구스 프로미스......를 지원한다는데 프로미스가 뭐여. 아 promise

https://www.zerocho.com/category/MongoDB/post/59b6228e92f5830019d41ac4

 

(MongoDB) Mongoose(몽구스) 프로미스

안녕하세요. 이번 시간에는 몽구스로 프로미스(promise)를 사용하는 방법에 대해 알아보겠습니다. 기본적으로 몽고DB(노드용 드라이버)는 콜백으로 결과값을 반환합니다. 콜백은 간단하지만, 다들

www.zerocho.com

CRUD는 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말

 

 

 

비동기 콜백함수 프로미스 async/await 등 개념 설명 짱임

https://joshua1988.github.io/web-development/javascript/promise-for-beginners/

 

자바스크립트 Promise 쉽게 이해하기

(중급) 자바스크립트 입문자를 위한 Promise 설명. 쉽게 알아보는 자바스크립트 Promise 개념, 사용법, 예제 코드. 예제로 알아보는 then(), catch() 활용법

joshua1988.github.io

 

728x90
728x90

깔고 

 

콘솔에서 

cd "경로"

cd 경로 로 해도 되더라

 

 

!!!

C:\data\db

폴더 없으면 실행안돼! 반드시 폴더 먼저 만들어야함

 

 

mongod

 

기본적으로 27017번 포트에서 실행됨

 

몽고디비 사용할때마다 mongod 명령어로 먼저 서버를 실행해야 함

 

(매번 실행하기 귀찮으면 명령 프롬프트를 관리자 권한으로 실행한 뒤 명령어 입력하는 방법도 있음 책353쪽 참고.)

 

 

몽고디비 프롬프트 접속하려면 같은 폴더에서 콘솔 하나 더 열어 mongo 명령어 입력

mongo

 

 

프롬프트가 >로 바뀌면 성공

지금은 누구나 몽고디비에 접속할 수 있으니 

관리자 계정을 추가하자

 

> use admin
switched to db admin
> db.createUser({user:'이름',pwd:'비밀번호',roles:['root']})  나 오타진짜 많이 낸다...안돼서 꽤 찾음
Successfully added user: { "user" : "이름", "roles" : [ "root" ] }

 

db.createUser 메서드로 계정 생성!

user에 사용자 이름 넣고 pwd 자리에 사용할 비번 입력 roles로는 현재 모든 권한이 있는root를 부여

 

아까 mongod를 입력했던 콘솔을 종료한 뒤

이번에는 mongod --auth명령어로 접속 (--auth는 로그인이 필요하다는 뜻)

 

 

 

다른창 끄고

여기서도 

exit

로 나와주고

 

mongod --auth 명령어로 접속 --auth는 로그인이 필요하다는 뜻

 

 

접속할 때 

앞으로 

cd 경로

 

admin -u 이름 -p 비번

하고

 

콘솔에 데이터베이스 만들거면  use 데이터베이스명

데이터베이스목록을 확인하는 명령어 show dbs

 

 

 

 

 

 

 

728x90
728x90

https://ko.javascript.info/debugging-chrome

 

Chrome으로 디버깅하기

 

ko.javascript.info

https://jybaek.tistory.com/717

 

노드를 더 우아하게. npm 이야기

노드를 더 우아하게 해주는 주변 프로그램인 npm 을 이해하도록 해보자. npm 은 Node.js Package Manager 로 단어 그대로 패키지 관리를 돕는다. 언뜻보면 python 의 pip 와 그 형상이 비슷해보이기

jybaek.tistory.com

https://p-iknow.netlify.app/node-js/path-moudle/

 

Nodejs, path module, __dirname, __filename 에 대해 톺아보기 - p-iknow's devlog

웹펙을 입문하려 할 때 처음 마주하게 되는게 entry 옵션이고, entry 옵션을 설정할 때 path.resolve("...") 처럼, node.js 의 path 모듈이 쓰이는 것을 볼 수 있다. 나를 포함한 입문자들이 대충 경로를 설정

p-iknow.netlify.app

 

728x90
728x90

설치 완료 후

 

 

mysql로 접속

 

설치된 폴더 경로로 들어가서 

cd 폴더경로

 

 

들어가서> mysql -u root -p

 

비번 입력하면 뜸!

 

나가고 싶으면

exit

 

데이터베이스 생성

create database movie_db default character set utf8;

 

영화정보 넣을거라서  movie_db로 넣었음

 

create database movie_db default character set utf8;

(MySQL이 기본적으로 알고 있는 구문을 예약어라고 부름 예약어는 소문자로 써도 되지만 대문자로 쓰는게 좋아

사용자가 직접만든 이름이랑 구분하기 위해서)

 

 

이거 사용할거야~

mysql> USE movie_db;

 

 

이전에 만든

데이트베이스 리스트 보고 싶으면

mysql> show databases;

 

그중에서 사용할 꺼 USE 데이터베이스

하고 

테이블 보기

mysql> show tables;

 

 

 

 

 

 



 

 

 

테이블(데이터가 들어갈 수 있는 틀) 생성하는 명령어

 

create table [데이터베이스명. 테이블명] 

 

mysql>  CREATE TABLE products(
    -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);

 

 

아까 USE 테이터베이스명 해서 

생략해도 됨

 

 

만들어진 테이블 확인하는 명령어 

DESC 테이블명

 

 

 

테이블  컬럼 추가

ALTER TABLE `테이블명` ADD `컬럼명` VARCHAR(50) NOT NULL;

 

mysql> ALTER TABLE `products` ADD `name` VARCHAR(50) NOT NULL;

 

악 에러 뜬 이유가 `` 뱁틱이어서 그랬음..ㅎㅎ

 

 

이렇게 괄호로 묶어서 한번에 여러 개 넣어줄 수도 있음

 

 

 

 

개념 정리하고 가자~~~

 

(아직 데이터를 안넣어서 책에 나온 예시로 정리)

 

컬럼과 로우

id  name  age married
1 zero 24 false
2 nero 32 true
3 hero 28 false

 

컬럼(column) : id, name, age,married 과 같은 세로줄 

(age 컬럼에는 24,32,28과 같은 정보 담겨있음)

로우(row) : 1,zero,24,false와 같은 가로줄. 

 

필드 : 컬럼과 로우가 교차하는 칸 하나

컬럼은 세로필드의 집합

로우는 가로 필드의 집합

테이블에 데이터를 넣을 때는 미리 컬럼을 정의해두고 컬럼에 맞춰 데이터를 넣으면 된다.

 

컬럼의 자료형

  • INT : 정수 의미. 소수까지 저장하고 싶다면 FLOAT 나 DOUBLE 자료형 사용
  • VARCHAR(자릿수) : 가변길이. 0~자릿수인 문자열 넣을 수 있음
  • CHAR(자릿수) : 고정길이 자료형. 부족한 자릿수만큼 스페이스가 채워짐
  • TEXT : 긴 글 저장할 때 사용. 수백 자 이내의 문자열은 보통 VARCHAR(자릿수)사용하고 그보다 길면 TEXT 사용
  • TINYINT : -128부터 127까지의 정수 저장할 때 사용. 1또는 0만 저장하면 불값(Boolean)과 같은 역할 할 수 있음
  • DATETIME : 날짜와 시간에 대한 정보 담고 있음. 날짜 정보만 담는 DATE / 시간정보 담는 TIME 자료형

 

(자료형 뒤) 옵션

  • NULL 과  NOT NULL  : 빈칸 허용할지 여부 묻는 옵션
  • AUTO_INCREMENT : 숫자를 저절로 올리겠다는 뜻 (데이터 넣으면 알아서 id로 1번부여, 다음 2번 부여 이렇게)
  • UNSIGNED : 숫자 자료형에 적용되는 옵션. 음수 무시되고 0~4294967295까지 저장가능.나이 컬럼에 체크해두는게 좋음
  • ZEROFILL : 숫자의 자릿수가 고정되어 있을 때 사용할 수 있음(예) INT(4)인데 숫자1넣으면 0001이 되는 식)
  • created_at 에는 DEFAULT now()라는 옵션 붙어있음. 현재 시각 넣으라는 뜻. now()대신 CURRENT_TIMESTAMP를 적어도 같은 뜻이 됨. 사용자 정보를 넣으면 created_at 컬럼에는 넣는 순간의 시각이 자동으로 기록됨.
  • 해당 컬럼이 기본 키인 경우에 PRIMARY KEY옵션을 설정. 기본 키란 로우를 대표하는 고유한 값을 의미

 

DEFAULT CHARACTER SET 을 utf8로 설정하지 않으면 한글이 입력되지 않으니 반드시 설정해야 함

 

 

 

테이블 잘못 만들었을 경우 제거하는 법

DROP TABLE [테이블명] ;

 

데이터 입력

INSERT INTO 테이블명 (필드,필드) VALUE ('테이터','데이터'..)

 

선택

Select * from products

전체 선택

 

select 필드, 필드 from 테이블 where 조건

(조건검사 : where 데이터 베이스 안에서 원하는 데이터를 조건에 맞게)

 

 

 

 

 

 

 

 

기본적인 mySQL 관계(비교)연산자 : 주어진 좌우 값을 비교하는 연산자
좌변과 우변이 같다
!= 또는 <>     좌변과 우변이 다르다
<   작다
<=   작거나 같다
크다
>= 크거나 같다

 

 

 

예시

 

 

논리연산자 : 참(true), 거짓(false) 두 가지를 가지고 비교하는 연산자
AND , && 비교하는 값 모두 참(true)여야 결과가 참(true)
OR , ||  비교하는 값 중 하나라도 참(true)이면 결과가 (true) 

예시

 

 

만약 글자에서 특정 부분 일치하는 데이터를 조회하고 싶다면!

LIKE

%는 다른 경우 들어갈 자리에 붙여줌

 

 

정렬하기 

order by

전체 선택해서 

openDate 기준으로 오름차순

 

오름차순 asc (안적어도 자동이긴 함)

내림차순 desc

 

 

특정 위치에 있는 데이터를 선택

LIMIT

상위부터 2까지

 

 

 

 

 

데이터를 3개를 건너뛴 다음에 데이터 1개

 

 

명령어 순서 지켜야함!

 

 

데이터를 수정할 때

update라는 명령어 써주면 됨

여러개 수정할 때

콤마, 사용

 

 

데이터 삭제

테이블 삭제 

DROP TABLE 테이블명;

데이터베이스 삭제

DROP TABLE 데이터베이스 이름;

728x90
728x90

앞에 올린 글

노드js express로 로그인 창만들때 

헷갈렸던 거

 

 

app.get   app.post 차이

 

 

그니까(내가 본 설명글 / 이것도 있음)

get은 /주소 보이는 방식이라서 /뒤에 주소 써주는데로 이동하고 띄우고 get써서 경로이동할 수 있게 하고
post는 주소 안보여주는 방식. 눈에 보이지 않는 주소요청 받아처리함. post에서는 서버에서 처리할 일 요청할 수도 있고 데이터를 전송할 수도 있음

 

앞에 쓴 글

코드 보면

html에서

post 로 form 써서 

메인페이지랑

로그인페이지 둘다 name 데이터 전송해서 썼어

 

app.js 에서는 경로 이동 쉽게 할려고 get쓰고

post로 정보 받아서 썼구나

오호...

 

res.send 특징 

res.write 써야돼? 여러개 쓰고 싶으면?

 

https://fierycoding.tistory.com/18

 

  • res.send(body), res.send(status, body) : 클라이언트에 응답을 보냄. 상태 코드는 옵션. 기본 콘텐츠 타입은 text/html이므로 text/plain을 보내려면 res.set(‘Content-Type’, ‘text/plain’)을 먼저 호출 해야한다. JSON을 보낼거면 res.json을 쓰자.

여기 req res 메서드 개념 잘 정리 되어있다!!

 

사실 정말 가려운 곳 못긁었는데 차차 해보면서 알아가도록 ..

 

 

키 값

name vaule 차이가 뭐야

넘길 때 왜 name 넘겨주면 value는 왜 쓰지..  

 

 

 

 

Value = The value attribute specifies the value of an element.

Name = name is only to post form data. The name definies what the name of the attribute will be as soon as the form is submitted. So if you want to read this attribute later you will find it under the "name" in the POST or GET Request. Whereas the id is used to adress a field or element in javascript or css.

 설명굿

 

아하!!

맞다

 

이분 오타내심 value

요거네 name이 전달되고 value는 입력 태그의 초기값

 

HTML - input태그와 그 속성 type, value, name - 입력태그 (1)

HTML - input태그와 그 속성 type, value, name 입력태그 (1)  오늘은 input태그와 그 속성 type, value, name에 대해서 알아 보도록 하겠습니다. 태그 기초부터 알아보기 전에 압타나 스튜디오를 직접 설치 하.

yangbari.tistory.com

오호라 헷갈렸어

728x90
728x90

만들기에 앞서서 

이거 먼저 만들어놔야

어떤 모듈 들어가있는지 확인할 수 있어

 

만드는 법  npm init

 

수업 듣다가 놓쳐서 에러뜨길래 물어보니까

 

 

 

스크립트에 

"start" : "nodemon app"

으로 바꿔줘야 했고

 

scripts 부분에 start 속성 잊지 말고 넣어야~!!

nodemon app을 하면 app.js를 nodemon으로 실행한다는 뜻이야  

 

코드 수정하면 노드몬이 서버 자동으로 재시작함 콘솔에서 rs 입력해서 수동으로 재시작할 수 있어

(개발용으로만 하는거 권장)

 

 

 

익스프레스 쓸거니까 밑에 애들깔아줘야 저렇게 들어가는 거임

 

npm i express

npm i -D nodemon

npm i morgan cookie-parser express-session dotenv body-parser

 

한번에 여러 개 깔 수 있음 (밑줄친건 안깔았나? 보면 없어서 안깔은거같기도 하고..)

 

원래 로그인페이지만 따라 만들고

과제로 다른 페이지로 넘어가는 거 함. 

 

일단 결과물

 

 

 

 

로그인 페이지 login.html

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Login Page</h1>
    <hr />
    <form method="post">
      <table>
        <tr>
          <td><label>UserName</label></td>
          <td><input type="text" name="login" /></td>
        </tr>
        <tr>
          <td><label>Password</label></td>
          <td><input type="password" name="password" /></td>
        </tr>
      </table>
      <input type="submit" name="" />
    </form>
  </body>
</html>

 

 

메인 페이지 main.html

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>메인페이지</title>
  </head>
  <body>
    <form method="POST">
      <h1>메인페이지</h1>
      <button name="loginpage" value="login-page">로그인페이지</button>
      <button name="naver" value="naver-page">검색페이지</button>
    </form>
  </body>
</html>

 

 

app.js

const express = require("express");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const morgan = require("morgan");
const fs = require("fs");
const app = express();
const port = 3001;

//미들 웨어 설정
app.use(morgan("dev"));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));

//라우터 설정
// app.get("/", (req, res) => res.send("Hello World"));
//들어가서 뜨는 로그인페이지 만약 쿠키들어있으면 성공 뜸
// app.get("/", (req, res) => {
//   if (req.cookies.auth) {
//     res.send("<h1>Login Success</h1>");
//   } else {
//     res.redirect("/login");
//   }
// });
// //메인페이지 추가해봄
app.get("/", (req, res) => {
  if (req.cookies.auth) {
    res.send("<h1>Login Success</h1>");
  }

  // fs.readFile("main.html", (error, data) => {
  //   res.send(data.toString());
  // });
  else {
    // res.redirect("/login");

    //send는 한번만 쓸수 있어서..end처럼끝내버리는거였음 그래서 밑에또부를때충돌남!!
    //여러개쓰고 싶으면 write
    //그거뿐만 아니라 불러올때 충돌나는것도 있음..
    fs.readFile("main.html", (error, data) => {
      res.send(data.toString());
    });
  }
});

app.post("/", (req, res) => {
  if (req.body.loginpage) {
    console.log(req.body);
    res.redirect("/login");
  } else req.body.naver;
  {
    res.redirect("https://www.naver.com/");
  }
});

//html페이지로
app.get("/login", (req, res) => {
  fs.readFile("login.html", (error, data) => {
    res.send(data.toString());
  });
});
//단순페이지요청(클라이언트가ㅏ요청한걸로 쿠키생성)
app.post("/login", (req, res) => {
  //쿠키생성
  let login = req.body.login;
  let password = req.body.password;
  console.log(login, password);
  console.log(req.body);
  if (login == "rint" && password == "1234") {
    res.cookie("auth", true);
    res.redirect("/");
  } else {
    res.redirect("/login");
  }
});

app.listen(port, () => console.log("example app listening on port"));

 

 

 

콘솔에서

cd 폴더주소

npm start

 

하면 

콘솔 넣은거 example app listening on port 잘 뜸

 

port 값 3001로 할당해놔서 들어가면

뜬다! 

 

버튼 두개 만들어놓은 이유가 button 눌렀을 때 name 값 잘 보내와지는지 볼라고

메인페이지 일때 

 

만약

localhost:3001/ 일때

요청.바디에 name=loginpage 이면

응답. 다시지시. localhost:3001/login

 

그것도 아니면 

요청.바디에.naver이면

응답. 다시지시.링크

 

 

로그인 페이지 넘어오면 

 

내가 get post 차이가 뭘까 에러날때마다 

다같이 얘기했음 이것도 찾아서 정리해봐야겠다

 

암튼 내가 이해한거는  

/login 일때

fs.readFile 이거는 파일 읽어서 불러오고 띄우고 

응답으로 res.send (express에서는 이거 사용)

 

 

요청.바디에.login을 login에 할당

할당하고

만약 input의 name=login이랑 정한 값이랑 같으면

응답.특정 쿠키를 만들어서

응답. "/"로 다시 불러와

 

그거 아니면

응답."/login" 불러와

 

 

 

설정한 값 잘 넣어서

쿠키값이 가지고 응답되었어!

그래서 "/" 다시 메인페이지로 돌아왔는데

왜 글자가 뜨냐면

 

 

 

 

 

 

 

만약에 

요청.쿠키들이.auth 면

응답.글자로~

 

이거 넣어서 임.

 

사실 처음에 잘되다가 

[nodemon] app crashed - waiting for file changes before starting...

 

다시 메인페이지, 버튼 두개 있는 창 띄우고 싶어서쿠키값을 오른쪽에서 삭제했는데에러가 막뜨는거야 

 

 

컨트롤 C해서

npm start

 

다시 구동했는데 됐다가 안됐다가...에러 자꾸 뜸

 

 

 

redirect를 많이해서 그런가 했는데 

위에 코드에도 적었지만

 

 

res.send 때문이었음

이게 응답과 동시에 끝내줘서 다음 동작에 안넘어가는 거야

 

그리고 원래 

 

  fs.readFile("main.html", (errordata=> {

      res.send(data.toString());

    });

 

이게 else안에 있는게 아니라 "/" 일때 맨 위에 있었고 그다음에 if였음

 

메인페이지 띄우라는 거랑

쿠키값 있을때 h1 글자창 띄우라는 거랑 충돌 났나봐

 

그래서 else 안에 넣어준거임

res.send도 하나만 쓸 수 있어서 if else 안에 넣어주고...

 

 

 

app.get

app.post 차이

 

 

res.send res.write 차이 궁금~

728x90
728x90

책 Node.js 교과서 개정2판 조현영 지음

const express = require("express");
//express모듈을 app변수에 할당
const app = express();
//app.set("port", 포트);로 서버가 실행될 포트를 설정
//process.env 객체에 PORT속성이 있으면 그값을 쓰고 아니면 3000
//app.set(키,값)
app.set("port", process.env.PORT || 3000);
//app.get(주소,라우터)는 주소에 대한 get요청 올때 어떤 동작할지 적는부분
//현재GET /요청시 응답으로 Hello,Express를 전송.
//익스프레스에서는 res.write나 res.end대신 res.send를 사용하면 됨
app.get("/", (req, res) => {
  res.send("Hello,Express");
});
//(GET요청 외에도 POST,PUT,PATCH,DELETE,OPTIONS에 대한 라우터를 위한 app.post,app.put~~메서드가 존재한다)
//listen은 http웹서버와 동일.포트연결하고 서버실행. 포트는 app.get('port')로 가져옴
app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기 중");
});

///단순 문자열 대신 HTML로 응답하고 싶다면 res.sendFile메서드 사용하면 됨
파일의 경로를 path모듈을 사용해서 지정해야함
const express = require("express");
const path = require("path");
const app = express();
app.set("port", process.env.PORT || 3000);

app.get("/", (req, res) => {
  //res.send('Hello,Express');
  res.sendFile(path.join(__dirname, "/index.html"));
});

app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기 중");
});

 

 

 

미들웨어도 해보기

////6.2 자주 사용하는 미들middle웨어
//미들웨어는 익스프레스의 핵심
//요청과 응답의 중간(미들middle)에 위치하여 미들웨어라 부름
//라우터와 에러 핸들러 또한 미들웨어의 일종
//미들웨어는 요청과 응답을 조작하여 기능을 추가하긷 하고 나쁜 요청을 걸러내기도함
//미들웨어는 app.use와함께 사용. >>>app.use(미들웨어)<<

//익스프레스 서버에 미들웨어를 연결해보자
const express = require("express");
//
const morgan = require("morgan");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const dotenv = require("dotenv");
const path = require("path");
//
dotenv.config();
const app = express();
app.set("port", process.env.PORT || 3000);
//app.use에 매개변수가 req,res,next인 함수를 넣으면 됨
//미들웨어는 위에서 아래로 순서대로 실행되고 요청과 응답사이에 특별한 기능추가할수있음
//next라는 세번째 매개변수를 사용했는데 다음 미들웨어로 넘어가는 함수임
app.use(morgan("dev"));
app.use("/", express.static(path.join(__dirname, "public")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
  session({
    resave: false,
    saveUninitialized: false,
    secret: process.env.COOKIE_SECRET,
    cookie: {
      httpOnly: true,
      secure: false,
    },
    name: "session-cookie",
  })
);

//

app.use((req, res, next) => {
  console.log("모든 요청에 다 실행됩니다.");
  next();
});
//현재app.get 라우터에 미들워에 두개 연결되어있음 이때도 next호출해야 다음 미들웨어로 넘어감
app.get(
  "/",
  (req, res, next) => {
    console.log("GET / 요청에서만 실행됩니다.");
    next();
  },
  (req, res) => {
    throw new Error("에러는 에러 처리 미들웨어로 갑니다.");
  }
);
//에러처리미들웨어는 매개변수가 err, req, res, next로 네개야
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).send(err.message);
});

app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기 중");
});

(솔직히 아직 이해는 잘 안되는데 설명 적어놓기)

 

dotenv 패캐지는 .env 파일을 읽어서 process.env로 만든다.

dotenv 패키지의 이름이 dot(점)+env인 이유다. process.env.COOKIE_SECRET에 cookiesecret 값이 할당된다.

키=값  형식으로 추가하면 된다. process.env를 별도의 파일로 관리하는 이유는 보안과 설정의 편의성 때문.

비밀 키들을 소스 코드에 그대로 적어두면 소스코드 유출 시 키도 유출됨. 따라서  .env 같은 별도의 파일에 비밀 키를 적어두고 dotenv 패키지로 비밀키를 로딩하는 방식으로 관리하곤함. .env 파일만 잘 관리하면 비밀키 지킬 수 있다.

 

 

터미널 이렇게 잘 뜸

(책에서 콘솔 이라는데 )

 

얘는 morgan 미들웨어에서 나오는 것. 

[HTTP 메서드] [주소] [HTTP 상태코드] [응답속도]-[응답 바이트]

 

를 의미함. 요청과 응답 한눈에 볼 수 있음

 

 

 

 

 

 

morgan 미들웨어 다음과같이 사용

app.use(morgan("dev"));

dev 이외에 combined, common, short, tiny 등을 넣을 수 있음 

인수 바꾸면 로그 달라져~

 

 

static 미들웨어

정적인 파일들을 제공하는 라우터(클라이언트의 요청 경로(path)를 보고 이 요청을 처리할 수 있는 곳으로 기능을 전달해주는) 역할을 함.

다음과 같이 사용

app.use("요청경로"express.static("실제경로"));

우리가 쓴거~

app.use("/"express.static(path.join(__dirname"public")));

 

함수의 니수로 정적 파일들이 담겨있는 폴더를 지정하면 된다. p237 이해안되면 책봐 미래의 나. 

예로

특정폴더명/stylesheets/style.css 는

http://localhost:3000/stylesheets/style.css  로 접근할 수 있음

css, js,이미지 파일들을  특정폴더에 넣으면 브라우저에서 접근할 수 있게 됨~

 

서버의 폴더 경로와 요청 경로가 달라서 외부인이 서버구조 쉽게 파악할 수 없어 보안에 좋아~

 

정적 파일들을 알아서 제공해줘서 4.3절(p190쿠키와 세션이해하기)처럼 fs.readFile로 파일 직접 읽어서 전송할 

필요 없음. 만약 요청 경로에 해당하는 파일이 없으면 알아서 내부적으로 next 포출함.

만약 파일을 발견했다면 다음 미들웨어는 실행되지 않음. 응답으로 파일 보내고 next를 호출하지 않으니까.

 

 

body-parser

요청의 본문에 있는 데이터를 해석해서 req.body객체로 만들어주는 미들웨어.

보통 폼 데이터나 AJAX 요청의 데이터를 처리함

단 멀티파트(이미지,동영상,파일) 데이터는 처리하지 못해서 뒤에 나오는 multer 모듈 사용하면 됨

 

 

body-parser 미들웨어 이렇게 씀

app.use(express.json());

app.use(express.urlencoded({ extended: false }));

 

body-parser는 JSON과 URL-encoded 형식의 데이터 외에도

Raw(요청의 본문이 버퍼 데이터일때 해석하는 미들웨어),

Text(덱스트 데이터 일때 해석하는 미들웨어)

형식의 데이터를 추가로 해석할 수 있음

 

 

 

npm i body-parser

 

이거 적어서 깔고 아래꺼 추가함

//body-parser
const bodyParser = require("body-parser");
app.use(bodyParser.raw());
app.use(bodyParser.text());

JSON은 JSON 형식의 데이터 전달 방식이고 URL-encoded 는 주소형식으로 데이터를 보내는 방식.

폼 전송은 주로 후자 사용함. 

urlencoded 메서드 보면 { extended: false } 라는 옵션이 들어있음 

이 옵션이 false면  노드의 querystring 모듈을 사용해 쿼리 스트링을 해석하고 true면 qs 모듈을 사용해서 쿼리스트링을 해석한다........

4.2절에서 POST와 PUT 요청의 본문 전달 받으려면 req.on('data') 와  res.on('end') 로 스트림 사용해야 했지

하지만 body-parser을 사용하면 그럴 필요없어 내부적으로 스트림을 처리해 req.body에 추가한다. 

 

 

cookie-parser

요청에 동봉된 쿠키를 해석해 req.cookies 객체로 만든다.

 

사용하는 법

app.use(cookieParser(비밀키)); 

해석된 쿠키들은 req.cookies 객체에 들어감예로 name=zerocho 쿠키를 보내면req.cookies는 {name:zerocho} 가 됨. 유효기간이 지난 쿠키는 알아서 걸러짐

 

쿠키는 클라이언트에서 위조하기 쉬워서 비밀키를 통해 만들어낸 서명을 쿠키 값 뒤에 붙임.서명 붙으면 쿠키가 name=zerocho.sign 과 같은 모양됨~서명된 쿠키는 req.cookies 대신 req.signedCookies 객체에 들어있음

 

 

cookie-parser가 쿠키 생성할 때 쓰이는 것은 아님!

 

쿠키 생성/제거 할때는 

res.cookie(키, 값, 옵션)

res.clearCookie 

메서드 사용해야함

 

옵션은 domain, expires,httpOnly,maxAge,path,secure 등있음

 

이렇게~

res.cookie("name""zerocho", {

  expires: new Date(Date.now() + 900000),

  httpOnly: true,

  secure: true,

});

res.clearCookie("name""zerocho", { httpOnly: truesecure: true });

 

쿠키를 지우려면 키와 값, 옵션도 정확히 일치해야 지워짐

단 expires 나 maxAge옵션은 일치할 필요 없어

 

signed 옵션은 true로 설정하면 쿠키 뒤에 서명이 붙음

서명을 위한 비밀 키는 cookieParser 미들웨어에 인수로 넣은 process.env.COOKIE_SECRET가 됨

 

 

 

express-session

세션 관리용 미들웨어

 

로그인 등 세션 구현하거나 특정 사용자 위한 데이터를 임시저장해둘 때 유용

세션은 사용자 별로 req.session 객체 안에 유지된다. 

app.use( session({

    resave: false,

    saveUninitialized: false,

    secret: process.env.COOKIE_SECRET,

    cookie: {

      httpOnly: true,

      secure: false,

    },

    name: "session-cookie",

  })

);

 

express-session 은 인수로 세션에 대한 설정을 받는다. 

resave는 요청이 올 때 세션에 수정 사항 생기지 않아도 세션을 다시 저장할지 설정하는 것

saveUninitialized 세션에 저장할 내역이 없더라도 처음부터 세션을 생성할지 설정하는 것

둘다 필요없어서 false로 한거야~

 

express-session은 세션 관리시 클라이언트에 쿠키를 보냄 

4.3절에서 배운 세션 쿠키가 이거다 이말임   p240 여기서 보충설명 다시 읽어봐라..

 

 

 

미들웨어의 특성 활용하기

app.use((req,res,next)=>{

    console.log('모든 요청에 다 실행됩니다.');

    next();

})

 

미들웨어는 req,res,next를 매개변수로 가지는 함수로서 

app.use

app.get

app.post

등으로 장착함 

 

특정한 주소의 요청에만 미들웨어가 실행되게 하려면 첫 번째 인수로 주소를 넣으면 된다~

app.use(

  morgan("dev"),

  express.static("/"path.join(__dirname"public")),

  express.json(),

  express.urlencoded({ extended: false }),

  cookieParser(process.env.COOKIE_SECRET)

);

 

 

위처럼 동시에 여러 개의 미들웨어를 장착할 수도 있고 다음 미들웨어로 넘어가려면 next함수 호출해야함.

위 미들웨어들은 내부적으로 next 호출하고 있어서 연달아 쓸 수 있는거.

next 호출하지 않는 미들웨어는 res.send나 res.sendFile 등의 메서드로 응답 보내야함 

express.static과 같은 미들웨어는 정적파일을 제공할때 next 대신  res.sendFile 메서도로 응답보낸다. 

따라서 정적파일 제공하는 경우 

express.json, express.urlencoded,cookieParser 미들웨어는 실행되지 않음

미들웨어 장착 순서에 따라 어떤 미들웨어는 실행되지 않을 수도 ㅇㅆ다느넉ㄹ 기억햊도오아

만약 next 도 호출하지 않고 응답도 보내지 않으면 클라이언트는 응답못받고 계속 기다리게 됨

 

app.use((reqresnext=> {

    req.data = '데이터 넣기';

    next();

  },(req,res,next)=>{

    console.log(req.data);//데이터 받기

    next();

  });

 

현재 요청이 처리되는 동안 req.data를 통해 미들웨어 간 데이터 공유할 수 있음

새로운 요청오면 req.data초기화됨 속성명이 꼭 data일 필요없지만 다른 미들웨어와 겹치지 않고 조심

app.set과의 차이 p244

app.set으로 익스프레스에서 데이터를 저장할 수 있다는 것을 배웠음 app.get 또는 req.app.get으로 어디서든지 데이터를 가져올 수 있음 하지만 app.set 사용안하고 req 객체에 데이터를 넣어서 다음 미들웨어로 전달해야하는 이유가 있다. app.set은 익스프레스에서 전역적으로 사용되므로 사용자 개개인의 값을 넣기에는 부적절하며 앱전체의 설정을 공유할 때 사용하면 됨 
req객체는 요청을 보낸 사용자 개개인에게 귀속되므로 req객체를 통해 개인의 데이터를 전달하는 것이 좋다

 

 

multer

멀티파트 형식으로 업로드할 때 사용하는 미들웨어

 

 

 

 

 

 

https://expressjs.com/ko/guide/routing.html

 

Express 라우팅

라우팅 라우팅은 애플리케이션 엔드 포인트(URI)의 정의, 그리고 URI가 클라이언트 요청에 응답하는 방식을 말합니다. 라우팅에 대한 소개는 기본 라우팅을 참조하십시오. 다음 코드는 매우 기본

expressjs.com

 

728x90
728x90

템플릿 엔진 Template Engine

템플릿 양식과 특정 데이터 모델에 따른 입력 자료를 합성하여 결과 문서를 출력하는 소프트웨어(또는 소프트웨어 컴포넌트)를 말한다


* Template : 공통적인 프레임을 미리 제작한 것

*웹 템플릿 엔진(Web Template Enging)이란? 웹 문서가 출력되는 템플릿 엔진을 말합니다. 즉, 웹 템플릿 엔진은  웹 템플릿들(Web Templates)과 웹 컨텐츠 정보(Content Information)를 처리하기 위해 설계된 소프트웨어입니다.

또한 웹 템플릿 엔진은 View Code(Html)와 Data Logic Code(Db Connection)를 분리해주는 기능을 합니다.

 

오 이사람 설명 잘한다 

https://show-me-the-money.tistory.com/56

 

템플릿 엔진이란 무엇인가?

자, 여기 인형을 만드는 업자가 있습니다. 이 업자는 인형을 만들기 시작한지 얼마 되지 않아 바느질에 익숙하지 않습니다. 고객으로부터 원하는 인형을 주문 받으면 업자는 창고에서 몸통, 눈,

show-me-the-money.tistory.com

 

 

 

출처

 

웹기술 - 템플릿 엔진, template engine 이란 무엇인가

서버 데이터를 정적 파일에 간단히 넘겨주는 기능 template engine 템플릿 엔진(template engine) 은 앱에...

blog.naver.com

 

[Template Engine] 템플릿 엔진(Template Engine)이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

템플릿 엔진(Template Engine) 이란?

템플릿 엔진이란 템플릿 양식과 특정 데이터 모델에 따른 입력 자료를 합성하여 결과 문서를 출력하는 소프트웨어(또는 소프트웨어 컴포넌트)를 말합니다. * Template : 공통적인 프레임을 미리 제

usefultoknow.tistory.com

 

728x90
728x90

HTTP(Hyper Text Transfer Protocol)

웹 상에서 클라이언트와 서버가 서로 정보를 주고받을 수 있도록 하는 규약

우선 클라이언트는 서버에 정보(데이터) 전송을 요청(Request)할 수 있는 클라이언트 소프트웨어(크롬, IE, 사파리 등 웹 브라우저가 대표적)가 설치된 컴퓨터를 의미한다. 클라이언트는 URL(Uniform Resource Locator)로 된 HTTP를 통해 서버에게 정보 송신을 요청합니다. 우리가 평소 쓰는 URL 구조를 구분해 살피면 각각은 아래와 같은 의미를 가짐.

 

URL의 예: http://www.wishket.com/company-intro
1. http://: 자원에 접근하기 위한 http 프로토콜
2. www.wishket.com: 서버의 위치
3. company-intro: 서버에서 컴퓨터가 요청한 자원의 위치 

 

클라이언트가 이렇게 정보 송신을 요청하면 서버는 대응한다. 서버는 응답하는(Response) 소프트웨어(아파치, nginx, IIS 등)가 설치된 컴퓨터를 의미한다. 서버는 클라이언트의 요청을 해석하고 클라이언트의 요청 및 서버 관리자가 설정한 알고리즘에 준하는 정보를 클라이언트에게 송신한다.

 

 

 

위의 내용을 정리하면 HTTP를 통해 이런 일이 이루어짐~

1. 클라이언트가 보고 싶은 정보를 서버에게 HTTP를 통해 요청.
2. 서버는 알맞은 응답 메시지 및 정보를 클라이언트에게 전달.
3. 응답 메시지 및 정보 중 HTTP바디 내용이 클라이언트가 설정한 클라이언트의 용처에 도달한다.

 

 

 

HTTP의 구조

HTTP는 애플리케이션 레벨의 프로토콜로 TCP/IP 위에서 작동한다. HTTP는 상태를 가지고 있지 않는 Stateless 프로토콜이며 Method, Path, Version, Headers, Body 등으로 구성된다.


하지만 HTTP는 암호화가 되지 않은 평문 데이터를 전송하는 프로토콜이라서 보안 취약

이 문제 해결하기 위해 HTTPS가 등장

 

HTTPS

HyperText Transfer Protocol over Secure Socket Layer, HTTP over TLS, HTTP over SSL, HTTP Secure 등으로 불리는 HTTPS는 HTTP에 데이터 암호화가 추가된 프로토콜이다. HTTPS는 HTTP와 다르게 443번 포트를 사용하며, 네트워크 상에서 중간에 제3자가 정보를 볼 수 없도록 공개키 암호화를 지원하고 있다.

 

‘HTTP vs HTTPS 차이’

 

바로 SSL(보안 소켓 계층) 인증서

 

사실 HTTPS는 쉽게 말해서 HTTP 프로토콜에 보안 기능을 추가한 것

 

SSL 인증서는 사용자가 사이트에 제공하는 정보를 암호화하는데, 쉽게 말해서 데이터를 암호로 바꾼다고 생각하면 쉽다. 이렇게 전송된 데이터는 중간에서 누군가 훔쳐 낸다고 하더라도 데이터가 암호화되어있기 때문에 해독할 수 없다. 그 외에도 HTTPS는 TLS(전송 계층 보안) 프로토콜을 통해서도 보안을 유지. TSL은 데이터 무결성을 제공하기 때문에 데이터가 전송 중에 수정되거나 손상되는 것을 방지하고, 사용자가 자신이 의도하는 웹사이트와 통신하고 있음을 입증하는 인증 기능도 제공하고 있습니다

 

 

사실 HTTPS로 전환하게 되면 검색엔진 최적화(SEO)에 있어서도 큰 혜택을 볼 수 있음

또한 가속화된 모바일 페이지(AMP, Accelerated Mobile Pages)를 만들고 싶을 때도 HTTPS 프로토콜을 사용해만 함 

 

 

 

출처

 

 

728x90
728x90

클라이언트가 보내는 요청의 단점, 누가 보낸 건지 몰라. 

대신 로그인 구현하면 되는데 로그인 한후에 새로고침해도 로그아웃 안되도록 

클라이언트가 서버에 누구인지 지속적으로 알려줘야함

쿠키

클라이언트 로컬에 저장되는

유효기간 있고 name=zerocho 처럼 단순한 Key-Value쌍의 작은 데이터 파일

 

쿠키의 구성요소

1. 이름 : 각각의 쿠키를 구별하는데 사용함

2. 유효시간: 쿠키의 유지시간

3. 도메인: 쿠키를 전송할 도메인

4. 경로: 쿠키를 전송할 요청 경로

5. 값: 쿠키와 이름과 관련된 값

 

 

 

동작방식

1. 클라이언트 -> 페이지 request 요청

2. 서버에서 쿠키를 생성

3. http헤더에 쿠키를 포함해서 respond 응답

4. 브라우저가 종료되어도 쿠키의 기한이 정해져 있지 않고 명시적으로 지우지 않는다면 반 영구적으로 쿠키가 남아있게됨

클라이언트 요청(쿠키가지지 않은 상태)
------------->
쿠키와 함께 응답
<-------------
쿠키와 함께 요청
--------------->
응답(쿠키 가진 상태)
<---------------
서버

 

 

 

세션 

브라우저가 종료되기 전까지 클라이언트의 요청을 유지하게 해주는 기술

 

세션은 어쨌든 쿠키를 기반으로 하고 있음

서버측에서 관리하긴함

 

 

 

사용자 많아질수록 서버 메모리 많이 먹어

클라이언트한테 아이디부여하는데 그게 세션아이디임

 

동작방식

  1. 클라이언트가 서버에 로그인 요청
  2. 서버는 클라이언트의 로그인 요청의 유효성을 확인하고(아이디와 비밀번호 검사) unique한 id를 sessionid라는 이름으로 저장
  3. 서버가 응답할 때 응답헤더에 set-cookie: sessionid:a1x2fjz를 추가하여 응답

   4 . 클라이언트는 이후 서버에 요청할 때 전달받은 sessionid:a1x2fjz쿠키를 자동으로 요청헤더에 추가하여 요청

   5. 서버에서는 요청헤더의 sessionid 값을 저장된 세션저장소에서 찾아보고 유효한지 확인후 요청을 처리하고 응답

 

세션의 내용은 서버에 저장되기 때문에 계속하여 늘어날 경우 서버에 부하가 발생

 

 

쿠키와 세션의 차이점

가장 큰 차이점 정보가 저장되는 위치

 

저장위치

쿠키는 서버에 저장되지 않고 클라이언트 로컬에 저장됨

세션은 서버의 자원을 써서 로컬과 서버에 저장됨

 

장단점

보안면에서는 세션이 좋고

속도면에서는 쿠키가 빠름

 

세션은 쿠키를 이용해 id만 저장하고 서버에 저장해

세션도 만료시간 정할 수 있지만 브라우저가 종료되면 만료시간 상관없이 날라감

쿠키는 브라우저 종료해도 파일로 남아있음

 

 

 

얘를 보완해서 JWT가 나옴 책에도 나와~

 

 

 

 

 

책보면서 직접 코드 따라해보기

 

cookie.js  

const http = require("http");
http
  .createServer((req, res) => {
    console.log(req.url, req.headers.cookie);
    res.writeHead(200, { "Set-Cookie": "mycookie=test" });
    res.end("Hello Cookie");
  })
  .listen(8083, () => {
    console.log("8083번 포트에서 서버 대기 중입니다");
  });

 

터미널

 경로 입력하고 서버대기 중 확인

 

 

createServer 메서드의 콜백에서는 req 객체에 담겨있는 쿠키 가져옴

쿠키는

req.headers.cookie 에 들어있음

req.headers는 요청의 헤더 의미 (쿠키는 요청과 응답의 헤더를 통해 오감)

응답의 헤더에 쿠키를 기록해야 돼서

res.writeHead 메서드를 사용함 

"Set-Cookie": "mycookie=test" 는 "다음에 오는 쿠키를 저장해라 : 다음"

 

 

 

 

로컬주소에 접속

req.url과 req.headers.cookies에 대한 정보를 로깅하도록 함

req.url은 주소의 path와 search부분을 알림 (사실 이부분 이해안돼서 찾아봤는데 이해안됨 그래도 읽어보자)

아 이건인가봐 (뒤늦게 발견)

 

 

 

 

위 코드까지는 쿠키 심기만 한거고

그 쿠키가 나인지를 식별 못하고 있음

이제는 사용자를 식별하는 방법을 알아보자

 

cookie2.html

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>쿠키&세션 이해하기</title>
  </head>
  <body>
    <form action="/login">
      <input id="name" name="name" placeholder="이름을 입력하세요" />
      <button id="login">로그인</button>
    </form>
  </body>
</html>

cookie2.js

const http = require("http");
const fs = require("fs").promises;
const url = require("url");
const qs = require("querystring");
//쿠키는 문자열임 이를 쉽게 사용하기 위해 js객체 형식으로 바꾸는  parseCookies함수
const parseCookies = (cookie = "") =>
  cookie
    .split(";")
    .map((v) => v.split("="))
    .reduce((acc, [k, v]) => {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});
http
  .createServer(async (req, res) => {
    const cookies = parseCookies(req.headers.cookie);

    //주소가 /login으로 시작하는 경우,url과 querystring모듈로 각각 주소와 주소에 딸려오는 query분석한다
    if (req.url.startsWith("/login")) {
      const { query } = url.parse(req.url);
      const { name } = qs.parse(query);
      const expires = new Date();
      //쿠키 유효시간을 현재시간 +5분으로 설정
      expires.setMinutes(expires.getMinutes() + 5);
      //헤더에 302응답코드,리다이렉트 주소와 함께 쿠키를 넣어
      //브라우저는 이 응답코드를 보고 페이지를 해당주소로 리다이렉트함
      //헤더는 한글을 설정할 수 없어서 name변수를encodeURIComponent메서드로 인코딩함
      res.writeHead(302, {
        Location: "/",
        "Set-Cookie": `name=${encodeURIComponent(
          name
        )}; Expires=${expires.toGMTString()};HttpOnly;path=/`,
      });
      res.end();

      //그 외의 경우(/로 접속했을때 등),먼저 쿠키있나없나확인. 없으면 로그인할 수 있는페이지보냄
      //처음 방문한경우 쿠키없으므로 cookie2.html 전송됨 쿠키있다면 로그인한상태로 간주해인사말보냄
      //name이라는 쿠키가 있는 경우
    } else if (cookies.name) {
      res.writeHead(200, { "Content-Type": "text/plain;charset=utf-8" });
      res.end(`${cookies.name}님 안녕하세요`);
    } else {
      try {
        const data = await fs.readFile("./cookie2.html");
        res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
        res.end(data);
      } catch (err) {
        res.writeHead(500, { "Content-Type": "text/plain;charset=utf-8" });
        res.end(err.message);
      }
    }
  })
  .listen(8084, () => {
    console.log("8084번 포트에서 서버 대기중입니다!");
  });

set-Cookie로 쿠키 설정할 때 

만료시간 expires 과 HttpOnly, Path같은 옵션 부여함

쿠키 설정할 때 각종 옵션 넣을 수 있고 옵션 사이 세미콜론(;) 써서 구분

쿠키에는 한글 쓰기, 줄바꿈 하면 안됨

  • 쿠키명=쿠키값  기본적 쿠키값 예) mycookie=test
  • Expires=날짜: 만료기한. 기본값은 클라이언트가 종료될 때까지
  • Domain= 도메인명:  쿠키가 전송될 도메인 특정할 수 있음. 기본값은 현재 도메인
  • Path=url : 쿠키가 전송될 url을 특정할 수 있음 기본값은'/'이고 이경우 모든 url에서 쿠키 전송할 수 있음
  • secure: HTTPS 일 경우에만 쿠키가 전송됨
  • HttpOnly: 설정 시 자바스크립트에서 쿠키에 접근할 수 없음 쿠키 조작을 방지하기 위해 설정하는 것이 좋음

 

 

 

 

 

이제 이름 노출안되는 버전

세션 방식.

const http = require("http");
const fs = require("fs").promises;
const url = require("url");
const qs = require("querystring");

const parseCookies = (cookie = "") =>
  cookie
    .split(";")
    .map((v) => v.split("="))
    .reduce((acc, [k, v]) => {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});

const session = {};
http
  .createServer(async (req, res) => {
    const cookies = parseCookies(req.headers.cookie);
    if (req.url.startsWith("/login")) {
      const { query } = url.parse(req.url);
      const { name } = qs.parse(query);
      const expires = new Date();
      expires.setMinutes(expires.getMinutes() + 5);
      const uniqueInt = Date.now();
      session[uniqueInt] = {
        name,
        expires,
      };
      res.writeHead(302, {
        Location: "/",
        "Set-Cookie": `session=${uniqueInt}; Expires=${expires.toGMTString()};HttpOnly;Path=/`,
      });
      res.end();
      //세션 쿠키가 존재하고 만료기간이 지나지 않았다면
    } else if (
      cookies.session &&
      session[cookies.session].expires > new Date()
    ) {
      res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
      res.end(`${session[cookies.session].name}님 안녕하세요`);
    } else {
      try {
        const data = await fs.readFile("./cookie2.html");
        res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
        res.end(data);
      } catch (err) {
        res.writeHead(500, { "Content-Type": "text/plain;charset=utf-8" });
        res.end(err.message);
      }
    }
  })
  .listen(8085, () => {
    console.log("8085번 포트에서 서버 대기 중입니다");
  });

 

코드 따라썼는데 자꾸 안된다고 에러뜸 

바로 이 에러~!!

NodeJS address already in use 

찾아서 따라해서 이전 포트? 종료하고 다시 함

로컬주소 들어가서 정보 입력하니까!

 

 아까 넣었던 쿠키 위에 쌓였다.

이 방식이 세션임

 

 

아까랑 다른 건 쿠키에 이름을 담아서 보내는 대신, uniqueInt라는 숫자값을 보냄. 사용자의 이름과 만료시간은 uniqueInt 속성명 아래에 있는 session이라는 객체에 대신 저장함

이제 cookie.session이 있고 만료기한 넘기지 않았으면 session 변수에서 사용자 정보를 가져와 사용한다.

 

 

안전하게 사용하기 위해서는 다른 사람들이 만든 검증된 코드를 사용하는게 좋대

그건 책 5장에서~~~

 

 

 

 

 

 

 

 

그.런.데.

내가 코드를 다 이해했다? 전혀 아니지요.

 

map 메서드

배열.map((요소, 인덱스, 배열) => { return 요소 });

const oneTwoThree = [1, 2, 3];
let result = oneTwoThree.map((v) => {
  console.log(v);
  return v;
});
// 콘솔에는 1, 2, 3이 찍힘
oneTwoThree; // [1, 2, 3]
result; // [1, 2, 3]
oneTwoThree === result; // false

reduce 메서드

배열.reduce((누적값, 현잿값, 인덱스, 요소) => { return 결과 }, 초깃값);

result = oneTwoThree.reduce((acc, cur, i) => {
  console.log(acc, cur, i);
  return acc + cur;
}, 0);
// 0 1 0
// 1 2 1
// 3 3 2
result; // 6

acc(누적값)이 초깃값인 0부터 시작해서 return하는대로 누적되는 것을 볼 수 있습니다. 초깃값을 적어주지 않으면 자동으로 초깃값이 0번째 인덱스의 값이 됩니다.

 

그렇다고 함 이것이 바로 설명 링크.. 읽어도 잘모르겠지만 암튼 보자 

 

 

 

 

 

 

 

NodeJS address already in use 문제 해결 - JooTC

NodeJS address already in use 문제 해결 방법 Error: listen EADDRINUSE: address already in use :::5000 현재 다른 프로세스에서 사용 중이라 해당 서비스를 시작할 수 없다는 에러입니다.

jootc.com

 

 

 

 

 

출처

728x90
728x90

개념 정리 <Node.js교과서>- 조현영 지음 책 요약

 

Node.js®는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임입니다.

 

 

기본개념

 

1.서버

네트워크를 통해 클라이언트레 정보나 서비스를 제공하는 컴퓨터 또는 프로그램

 

노드는 서버 애플리케이션 실행하는데 제일 많이 사용됨.

서버는 클라이언트의 요청에 대해 응답해야 함. 

 

 

2. 자바스크립트 런타임

노드는 자바스크립트 런타임. 런타임은 특정 언어로 만든 프로그램들을 실행할 수 있는 환경을 뜻함

 

 

<노드의 내부 구조>

Node.js Core Library
Node.js Bindings
V8 (  -> 오픈소스 자바스크립트 엔진) libuv (  -> 비동기 I/O)

 

3. 이벤트 기반 event-driven

이벤트(클릭, 네트워크 요청 등과 같은)가 발생할 때 미리 지정해둔 작업을 수행하는 방식 의미한다.

특정 이벤트가 발생할 때 무엇을 할지 미리 등록해놔야하는데 이걸 이벤트 리스너에 콜백함수를 등록한다고 표현한다.

발생한 이벤트가 없거나 발생했던 이벤트를 다 처리하면 노드는 다음 이벤트가 발생할 때까지 대기.

 

<이벤트 기반>

시스템 2. 이벤트 발생
--------------------->

<---------------------
3. 등록된 콜백함수 호출
이벤트 리스너

1. 이벤트 리스너에 콜백함수 등록

이벤트 기반 모델에서는 이벤트 루프라는 개념 등장. 여러 이벤트 동시발생시 어떤 순서로 콜백함수를 호출할지를 이벤트 루프가 판단함.  노드와 자바스크립트에서 이벤트 루프는 정말 중요 개념~!

 

이벤트 루프:
이벤트 발생시 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 실행순서결정하는 역할 담당. 노드가 종료될 때까지 이벤트 처리위한 작업을 반복해서 루프라고 부름.
백그라운드:
setTimeout 같은 타이머나 이벤트 리스너들이 대기하는 곳. 자바스크립트가 아닌 다른 언어로 작성된 프로그램이라고 봐도 된다. 여러 작업이 동시에 실행될 수 있음
테스크 큐:
이벤트 발생 후, 백그라운드에서는 테스크 큐로 타이머나 이벤트 리스너의 콜백 함수를 보낸다. 정해진 순서대로 콜백들이 줄 서 있어서 콜백 큐라고 부른다. 보통은 완료된 순서대로 서있지만 특정한 경우 순서 바뀌기도함.

 

4. 논 블로킹 I/O 

 

작업은

동시에 실행될 수 있는 작업과

동시에 실행될 수 없는 작업있음 

 

자바스크립트 코드는 동시에 실행될 수 없음

하지만 js상에서 돌아가는게 아닌 입력Input 출력Output 작업같은 건 동시처리 가능

 

(파일 시스템 접근이나 네트워크를 통한 요청 같은 작업이 I/O의 일종)

 

이런 작업시 노드는 

논블로킹 방식으로 처리하는 방법을 제공한다. 

 

<백그라운드 작업완료 확인 여부>
논블로킹:
이전 작업이 완료될 때까지 대기하지 않고 다음작업 수행
블로킹:
이전 작업 끝나야만 다음작업 수행

 

 

노드는 I/O 작업을 백그라운드로 넘겨 동시에 처리하곤 함.

작업 순서에 따라 작업 시간 단축되어 성능 크게 달라짐! 동시에 처리될 수 있는 I/O 작업이라도 논블로킹 방식으로 코딩하지 않으면 의미 퇴색되므로 논 블로킹 방식으로 코딩하는 습관 들이기!!

 

하지만 아무리 논블로킹 방식으로 코드 작성해도 우리가 전부 작성한 코드는 서로 동시에 실행되지 않기에 소요시간이 짧아지진 않는다. 실행 순서만 바뀔뿐. 그래도 논블로킹을 통해 실행 순서를 바꿔줌으로써 그 작업 때무에 간단한 작업들이 대기하는 상황을 막을 수 있다는 점에서 의의가 있다. 

논블로킹과 동시가 같은 의미가 아니라는 것도 알아두기 . 동시성은 동시 처리가 가능한 작업을 논 블로킹 처리해야 얻을 수 있음.

노드에서는 동기와 블로킹이 유사하고 비동기와 논블로킹이 유사함.

<함수가 바로 return되는지 여부>
동기(synchronous : 동시에 일어나는):
블로킹 방식에서는 백그라운드 작업 완료 여부를 계속 확인하며, 호출한 함수가 바로 return되지 않고 백그라운드 작업이 끝나야 return된다. 
비동기(Asynchronous : 동시에 일어나지 않는):
논블로킹 방식에서는 호출한 함수가 바로 return되어 다음 작읍으로 넘어가며, 백그라운드 작업 완료 여부는 신경쓰지 않고 나중에 백그라운드가 알림을 줄 때 비로소 처리함.

 

동기:  요청과 결과가 한 자리에서 동시에 일어남.설계가 매우 간단하고 직관적이지만 과가 주어질 때까지 아무것도 못하고 대기해야 하는 단점이 있고, 

비동기:  요청한 그 자리에서 결과가 주어지지 않음 동기보다 복잡하지만 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 장점이 있습니다.
출처: https://private.tistory.com/24 [공부해서 남 주자]

 

 

 

5. 싱글스레드

 

스레드가 하나뿐이라는 것.

 

프로세스:  운영체제에서 할당하는 작업의 단위.

노드나 웹브라우저 같은 프로그램은 개별적인 프로세스임. 프로세스 간에는 메모리등의 자원 공유안해

스레드: 프로세스 내에서 실행되는 흐름의 단위.

프로세스는 스레드를 여러 개 생성해 여러 작업을 동시에 처리할 수 있음. 스레드들은 부모 프로세스의 자원공유해. 같은 주소의 메모리에 접근 가능해 데이터를 공유할 수 있어

 

 

 

노드는 싱글 스레드?

엄밀히 말하면 싱글 스레드로 동작하지 않음

노드를 실행하면 먼저 프로세스 하나 생성됨 그 프로세스 안에서 스레드 여러개 생성함 . 우리가 직접 제어할 수 있는 스레드는 하나뿐! 그래서 흔히 노드가 싱글 스레드라고 여겨짐.

스레드는 작업을 처리하는 일손. 하나의 스레드만 직접 조작할 수 있으니까 일손이 하나인 것임.

블로킹이 발생할 것 같은 경우에는 논블로킹 방법으로 대기시간을 최대한 줄인다. 

 

 

<노드가 싱글 스레드로 동작하지 않는 두 가지 경우>

스레드풀(Thread Pool)

노드가 특정 동작을 수행할 때 스스로 멀티 스레드를 사용한다. 대표적인 예로 암호화(3.5.5절), 파일입출력(3.6절),압축(3.6.2절) 등이 있다

워커 스레드(Worker Thread)

이제 노드에서도 멀티 스레드를 사용할 수 있게한 기능. 우리가 직접 다수의 스레드를 다룰 수 있음. CPU 작업(연산이 많은 작업)이 많은 경우 워커 스레드를 사용하면 된다.

 

 

 

서버로서의 노드

 

노드는 기본적으로 싱글 스레드, 논블로킹 모델을 사용함. 

따라서 노드 서버의 장단점은 싱글 스레드, 논블로킹 모델의 장단점과 비슷함.

 

노드는 CPU부하가 큰 작업에는 적합하지 않음 연산을 많이 요구하면 스레드 하나가 혼자 감당하기 어려워!

노드는 개수는 많지만 크기는 작은 데이터를 실시간으로 주고받는데 적합함.

네트워크나 데이터베이스, 디스크 작업 같은 I/O에 특화되어있음

 

<노드의 장단점>

장점 단점
멀티 스레드 방식에 비해 적은 컴퓨터 자원 사용 기본적으로 싱글 스레드라서 CPU코어를 하나만 사용
I/O 작업이 많은 서버로 적합 CPU작업이 많은 서버로는 부적합
멀티 스레드 방식보다 쉬움 하나뿐인 스레드가 멈추지 않도록 관리가 필요함
웹 서버가 내장되어있음 서버 규모가 커졌을 때 서버를 관리하기 어려움
자바스크립트를 사용함 어중간한 성능
JSON형식과 쉽게 호환됨  

 

 

 

 

 

 

 

728x90
728x90

0811 복습

 

"구조 가상 클래스"

 

웹문서의 구조를 기준으로 특정 위치에 있는 요소를 찾아 스타일 적용할 때 사용

일반적으로 스타일 적용할 때 class id 선택자 사용….

요소가 여러 개 나열되어 있는 경우에는 굳이 classid를 쓰지 않고 스타일을 지정(몇 번째인지 구분해서)할 수 있다.

 

only-child : 부모 안에 자식요소가 하나만 존재할때 자식 요소를 선택            
first-child : 부모안에 있는 요소중에서 첫번째 자식을 선택            
last-child : 부모안에 있는 요소중에서 마지막 자식..            
nth-child(n) : 부모안에 있는 모든 요소 중에서  n번째 자식을 선택            
nth-last-child(n) : 부모안에 있는 모든 요소 중에서 끝에서  n번째 자식을 선택            


A:only-target-of : 부모안에 A요소가 하나만 있을때            
A:first-of-type : 부모안에 있는 A요소 중에서 첫번째 요소 선택            
A:last-of-type : 부모안에 있는 A요소 중에서 마지막 요소 선택            
A:nth-of-type(n) : 부모안에 있는 A요소 중에서 n 번째 요소 선택            
A:nth-last-of-type(n) : 부모안에 있는 A요소 중에서 끝에서 n 번째 요소 선택

(선택자 정보 링크)

 

 

 

 

 

 

 

 

 

*

 

 

 

728x90
728x90

밀린 복습 0811

 

가상클래스 사용하는데 

웹문서에서 같은 사이트나 다른 사이트 이동할 때 링크이용한다.

같은 문서안에서 다른 위치로 이동할때는 앵커 사용해

이때 타겟이라는 선택자를 사용하면 앵커로 연결된 부분이 앵커의 목적지가 되는 부분에 쉽게 적용할수있다

 

 

같은 문서 안에서 다른 위치로 이동할때는 앵커를 이용            
:target->앵커로 연결된 부분, 즉 앵커의 목적지가 되는 부분의 스타일을 쉽게 적용

연습삼아 다시 해봄
링크를 id 경로로 달았으(위에거는 수업꺼)

 

 

enabled, disabled ->요소의 사용 여부에 따라 스타일 적용
(사용할 수 있을때는 enabled /사용할 수 없을때의 스타일 지정disabled씀)        
checked ->선택한 항목의 스타일을 적용 (라디오 박스나 체크박스 쓸 때 체크박스 유용하게 씀)

 

 

 

 

+그 인풋에 체크박스 해보다가 하나만 선택되는거 왜 안돼~ 해보다가

참고로 이름 이따구로 지으면 안됨.;;

input type="radio" 얘 단일 선택

input type="radio" 

input type="checkbox" 얘가 걍 체크박스~ 더라구..허허..

 

여러 타입이 있었다

 

 

 

 

+오 이렇게 링크 달수도 있구만유(복습하는거면서 처음보는 척)

 

 

 

+

required

 

<input> 태그의 required 속성: 반드시 채워져 있어야 하는 입력 필드를 명시

 

 

 

 

728x90
728x90

https://pridiot.tistory.com/38?category=875371 

 

0816 수업 빠져서 물어물어 공부

다들 잘 설명해주심..

 

[Java] for문을 활용한 별(*)찍기

공부했던 자료 정리하는 용도입니다. 재배포, 수정하지 마세요. for문을 활용해서 여러 가지 모양을 출력하기 다중  for 문을 활용한다면 여러 가지 모양을 출력할 수 있다. 출력할 모양이 어떤

pridiot.tistory.com

 

 

https://hianna.tistory.com/368

 

[Javascript] for문을 이용해서 별찍기

지난번에는 for문의 기본적인 사용방법을 알아보았습니다. [Javascript] 반복문(1) - for 이번에는 for문을 응용한 다양한 형태의 별찍기 예제를 공유합니다. 정사각형 별찍기 See the Pen 반복문 by anna (@h

hianna.tistory.com

 

https://wikidocs.net/212

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

 

 

https://velog.io/@max9106/Java-%EB%B0%98%EB%B3%B5%EB%AC%B8-for-while-ffk4a7p2a2

 

[Java] 반복문 ( for / while )

반복문 코드를 자동으로 반복시켜주는 것 반복문의 종류 1) for 2) while(do while 포함) for문 int i = 0 //나를 도와주는 변수 정의 i<10 //조건 i++ //나를 도와주는 변수 업데이트 for문은 조건 검사 후 참일

velog.io

 

https://mingnol2.tistory.com/86

 

[JAVA] 반복문 : while문을 이용한 무한루프

while문 특정 조건을 만족할 때 까지 무한정 돌아간다. 무한 루프를 만들기 쉽다. while(i 무한 루프 만들기 무한루프를 만들려면 while문 조건에 항상 참이되는 식을 넣으면 된다. 주의할점은 탈출구

mingnol2.tistory.com

 

이건 동기 언니가 알려준 사이트~

https://ko.javascript.info/

 

모던 JavaScript 튜토리얼

 

ko.javascript.info

http://sinbiweb.co.kr/web/home.php?go=item&sol_num=4 

 

신비웹

홈페이지제작, 쇼핑몰제작, 온라인광고, 문의전화 1544-0835

sinbiweb.co.kr

이것두.. 웹디자인 참고용으로 좋다고 알려줌

728x90
728x90

가상 선택 클래스, 가상요소

 

유저가 어떤걸 클릭을 한다거나 마우스포인터를 올려놨다 그때

특정동작하고 싶음 그때 사용

사용자 동작에 반응하는 녀석들 자주써!

가상클래스 선택자
:link
방문하지 않는 링크에 스타일 적용
:visited
웹문서의 링크중에서 한번 이상 방문한 링크에 스타일 적용
:hover
마우스 포인터를 올려놓을 때 스타일 적용
:active
웹요소의 링크나 이미지등을 활성화 했을 때, 클릭햇을 때 스타일을
지정
:focus
웹 요소의 초점이 맞추어져있을 때 스타일 적용

 

navi에 a(하위선택자) 얘기하는거겠지?

거기에 반응형..

 

마우스 갖다대면 이렇게~

 

 

참고로

<a href=“URL”>
<a> 태그href 속성은 링크된 페이지의 URL을 명시합니다
728x90
728x90

0810화요일 수업기록

 

저번시간 블록레벨이랑 인라인레벨했었는데

display속성사용하면 블록레벨 요소랑 인라인 레벨

요소를 서로 바꿔서 사용할 수 있다.

display속성은 주로

웹문서의 내비게이션(옆으로 뜨는 카테고리 창같은거)

가로배치한 내비게이션

 

 

내비게이션을 만들면서 메뉴항목을 가로로 배치할 때 주로 사용

이미지를 표형태로 배치할 수도 있음

display : block ->인라인 레벨 요소를 블록레벨 요소로 만든다.    
display : inline ->블록레벨 레벨 요소를 인라인 요소로 만든다.    
display : inline-block ->인라인과 블록의 속성을 모두 가지고 있고 마진과 패딩을 지정할수 있다.    
display : none ->해당 요소를 화면에 표시 하지 않는다.

내비게이션 구성할 때 <nav>라는 태그를 사용합니다

 

인라인 블록 걸어서
가로로

 

 

 

 

 

 

p태그 넣고 이미지 나란히 하고 싶은데

p태그는 블록레벨이라 이미지와 나란히 한줄못써

그럴때는 플롯이라는 속성이용하면돼

거기서 이미지 표시하고 주변에 택스트 감싸게

 

 

float  : left ->해당 요소를 문서의 왼쪽에 배치                  
         right->해당 요소를 문서의 오른쪽에 배치                  
         none->좌우 어느쪽에도 배치하지 않는다 default

플롯은 웹요소를 붕떠있게하는 거 그게 왼쪽구석이냐 오른쪽구석이냐 플롯 레프트 롸이트 아무것도 아닌 none

이렇게 3개있음

 

 

이렇게 왼쪽 배치하면

그다음에 넣는 애들도 똑 같은 속성값 반영되어버림

내가 플롯요소를 하나에만 넣고 싶은데 밑에 해제안하면

밑에도 전달됨

그래서 플롯 속성더이상 유효하지 않다는 속성 넣어줘야함

클리어!!

 


clear left -> float left 해제 
       right-> rigt해제
       both->둘다해제

왼쪽부터 차례대로 정렬됨배치됨

근데 3은 플롯 지정안해서

웹브라우저 기본 흐름대로 배치된거.

클리어주면!!

클리어 주면 이렇게~

 

 

 

플롯레프트랑 인라인블록이랑 뭔차이냐~

눈으로는 동일. 똑같이 가로 배치

근데인라인블록은 차이가 있어.

결과화면은 같은데

 

인라인 블록으로 세팅하면 가로로 배치를 하긴하지만

마진이랑 패딩값을 기본으로 갖고 있고

 

플롯으로 배치하면 가로배치될 때 마진이랑 패딩값이 없어

 

플롯으로 요소 배치할 때 만약 마진이랑 패딩필요해 그러면 지정 별도로 해야되고

클리어 속성으로 플롯레프트 해제해야한다.!!

플롯이랑 클리어 속성 잘 쓰면 레이어만들 때 잘 활용할 수 있다

 

 

 

 

 

 

미리 레이아웃 그림으로 그려놓고 세팅하는게 제일 좋다! 헤더는 주로 웹페이지 상반부

본문은 메인컨텐츠

레이아웃짤 때 미리 구성해~

제목 위에 들어가기

카테고리 나타낼거 사이드바.

본문 메인 컨텐츠영열

Footer 맨 밑에 들어갈거

이런식으로
웹브라우저 기본값 리셋하는 거임

 

 

컨테이너 내용전체 너비

 

내가 따라 하면서 안됐던게

처음에 정한 전체 너비보다

사이드바, 본문의 두 너비 합한 게 커서 그랬음(그래서 플롯써도 옆에와서 안붙고 밑에 있었음)

 

근데 처음에 전체 컨테이너 잡을 때 너비만 지정하고 세로값은 안줘서 궁금함..

 

 

 

position            
static : 문서의 흐름에 맞춰 배치.default (위치를 지정해서 배치)       
relative : 위칫값을 지정할수 있다는 점을 제외하면 static      
absolute : relative값을 사용한 상위요소 기준으로 위치를 지정해서 배치        
fixed : 브라우저 창을 기준으로 위치를 지정해 배치 (고정역할)

absolute를 사용할때 주의해야 할점

 

위치값을 지정하면 요소중에서 relative를 사용한 요소를 기준으로 위치를 지정....

만약 부모요소중에 없으면 상위요소를 찾고 이것마저 없으면 더 위의 요소를 찾는다.

 

absolute를 쓰고 싶다면 부모요소에 relative를 지정해야 원하는 대로 배치할수 있다.

바디 기준으로 왼쪽, 위쪽에서 50픽셀만큼 떨어지게

 

화면을 줄여도 고정되어있는 사각형 

만들기~~

relative-2를 (100에서 200으로 바꿨지만) 왼쪽 200 위로 -50
고정~

 

Absolute를 사용할 때 주의할점

위치값을 지정하면 요소중에서 relative를 사용한 요소를 기준으로 위치를 지정함

만약 Absolute을 준 요소, 의 상위를 찾는데 만약 

근데 그 위에 요소도 없어 그러면 더 위에 올라가서 찾게 됨.

 

(=만약 부모요소에서 없으면 상위요소를 찾고

이것마저 없으면 또 위로 올라가서 찾아~

할아버지 찾고~)

결론 어떠한 요소에 Absolute를 쓰고 싶다면

부모 요소에 반드시 relative를 지정해야 원하는대로 배치할 수 있다.

 

 

background-repeat        
repeat : 브라우저 화면에 가득찰때까지 가로세로 반복 default        
repeat-x : 브라우저 화면 너비에 가득 찰때까지 가로로 반복        
repeat-y : 브라우저 화면 높이에 가득 찰때까지 가로로 반복        
no-repeat : 한번만 표시하고 반복 ㄴㄴ                

background-position  : 배경이미지의 수평,수직 위치값을 설정할수 있음.

값두개있는거-> 레프트는 수평 center는 수직

하나있으면 수평위치값 (수직 위치값은 50이나 센터로 간주)

사실 50,센터? 하는 말 다 적긴했는데 지금보니 뭔소리인지 잘모르겠네

 

박스 모델에 패딩이나 테두리가 있다면 배경이미지를 패딩까지 표시하거나 테두리까지 포함해서 표시 할수 있음.
배경 이미지를 적용할 범위는 background-origin속성으로 지정함.    
content-box : 박스 모델에서 내용부분에만 배경이미지 표시 default   
adding-box : 박스 모델에서 패딩까지 배경 이미지 표시    
border-box : 테두리까지...

예시)
 background-origin: content-box;
background-attachment

scroll : 배경이미지도 스크롤 default
fixed:  화면을 스크롤 하면 배경이미지는 고정되고 내용만 스크롤

예시)  background-attachment: fixed;
background-size
background-size: cover; 배경이미지로 요소 모두 덮어버림
background-size: contain; 배경이미지가 다 들어오도록 잡음

 

 

 

 

하위선택자

이게 바로 하위선택자 공백끼고 넣어야돼 ~

 

특정 요소를 기준으로 그안에 포함되어있는 녀석 :하위요소

현재기준으로 한 단계아래 자식, 또 아래는 손자.

 

하위선택자 쓰면 부모요소에 선택된 모든 하위요소 선택됨

 

하위(자식,손자 밑에 애들 다~)선택자 

 

 

자식선택자

자식에만~!

자식선택자(바로 밑 자식만)

 

인접형제 선택자 라는게 있어
웹문서에서 부모 요소가 같을 경우를 형제관계라고 함

형제요소 중에서 첫번째 동생요소만 선택하는 것을 인접 형제 선택자
요소1+요소2

형제요소 중에서 전체 동생요소 선택하는 것을 인접 형제 선택자
요소1~요소2


(밑에 색 다른거 예전 설정이라 무시)

 

 

 

참고로 h1,p {} 랑 다른게

그렇게 하면 h1의 설정값도 저렇게 바뀜

 

 

 

 

 

 

속성 선택자

태그안에 사용하는 속성값에 따라서

태그를 속성하는 역할상황에 맞는 스타일 지정하기쉬움 

대괄호 안에다가 원하는 속성 넣어주면됨

 

 

 

 

스타일

 

스타일

[] 이게 찾으려고 하는 속성의 이름
ddd 부분이 스타일

특정부분만 바꿈

728x90
728x90

0809수업기록

 

 

 

헤드사이에

 

 

속성넣고 속성값은 세미콜론(;)으로 구분!!

포지션 꼼꼼하게 봐야돼! 자주쓰지만 그만큼 실수 할수도 있음

 

* {} 
전체 선택

 

마진 값과 페딩값을 

0해놓고 많이 시작하는 듯함.

 

스타일 시트는 크게 두 가지로 구분됨

1. (기본스타일) 웹브라우저  스타일 이랑

2.사이트제작자가 만드는 사용자 스타일

 

 

사용자 스타일에서도 나뉨 크게 3개로

1. 인라인 스타일(간단한 스타일 적용하는거.)

2. 내부 스타일시트(하나의 웹문서 스타일 써주는 방금한게 내부스타일)

3. 외부스타일(링크불러서 걸어주는거 가장 많이 쓴다함)

 

인라인 스타일
내부 스타일

선택자

1. 전체 선택자: 스타일을 문서의 모든 요소에 적용할 때 사용.

주로 모든 하위 요소에 스타일을 한꺼번에 적용할 때 사용.

*{속성:…}  이렇게 생김

전체스타일은 주로 기본 스타일초기화할 때 자주사용

 

기본값이지만 이렇게 마진8 로 여백이 있음! 그래서 전체선택해서 마진 0 으로~

마진/ 페딩: 웹문서 내용을 브라우저 창에서 바짝붙지 않게 하는 여백 

 

 

2. 타입 선택자: 특정 태그를 사용한 모든 요소에 스타일 적용

= 타입 선택자를 사용해 스타일을 지정하면 해당 태그를 사용한 모든 요소에

적용된다. (타입선택자나 태그 선택자 같은말~)

ex) h태그,p태그

 

3. 클래스 선택자

같은 태그라도 일부는 다른 스타일을 적용하고 싶다면 클래스 선택자를

사용한다

 

얘는 태그에다가 클래스선택자를 넣어주면 돼~

class 스타일로, accent 랑 bg 들어감!

 

클래스 선택자는 클래스 이름을 사용해서 다른 선택자와 구별함.

 . 클래스명 {속성넣어줌}

요소 하나에 클래스 스타일을 2개 이상 적용할수있는데 그럴때는 공백으로

구분한다!!

 

class이름은 기억하기 쉽게 임의로 지정하면 됨!!! bg백그라운드

이름이면 name이렇게 누가봐도 알수있게!!!

 

 

4. id 선택자

클래스 선택자랑 거의 비슷해 그거랑 마찬가지로

웹문서의  특정부분 선택해서 스타일 지정할 때 사용

얘는 점대신 샵쓴다. #

이 기호만 틀리다 틀리지 정의같음

 

#아이디명 {스타일어쩌구}

차이는 있음 클래스 선택자는 문서에서 여러 번 적용할 수 있음. id선택자는

문서에서 한번만 적용할 수 있음. 이러한 성질 때문에id선택자는 중복해서

적용할수없으므로 주로 문서의 레이아웃과 관련된 스타일을 지정하거나

아니면 웹요소에 자바스크립트 프로그램을 사용하면서 요소를 구별할 때 사용

margin
오토하면 중앙배열됨
볼더에다가 속성값 솔리드(점선 등 다른걸로 바꿀 수도 있음)까지 넣어야완성!!

 

5. 그룹선택자

같은 스타일 규칙을 사용하는 경우 (콤마) ,로 구분해서

선택자를 나열한 다음

스타일 규칙을 적용

h1,p{속성..}

1em이 16픽셀임

 

 

이렇게 넣으면
요렇게 리스트이미지(작은 픽셀사진넣음) 이렇게 바꾸기도 가능
폰트사이즈도 조정가능
가로, 세로, 번진정도

<header>

 

 

스타일시트에서는

우선순위 존재하는데, 위에서 아래로 적용된다.

(css는 우선순위가 있는 스타일시트다~)

 

CSS = 캐스캐이딩(위에서 아래로 흐르는)
스타일끼리 충돌,중복되지 않도록 막아주는 중요한 개념

 

스타일이 충돌하지 않게하는 방법으로 두 가지정도가 있음

 

1. 스타일 우선순위:

스타일 규칙의 중요도와 적용 범위에 따라 우선순위가 결정된다.

그 우선순위에 따라 위에서 아래로 스타일을 적용한다.

 

2. 스타일 상속:

태그의 포함관계에 따라 부모요소의 스타일을 자식 요소로

위에서 아래로 전달!

 

1. 스타일 우선순위 

: 어떤 스타일을 먼저 적용할거냐 결정하는 규칙

 

 <3가지 개념에 따라 지정>

1. 얼마나 중요하냐.

 

웹브라우저에서 내용표시할 때 css스타일만 적용하는게 아니고

컴퓨터 사용자스타일, 웹문서 제작자 스타일, 웹브라우저 디폴트 정해놓은 스타일 3가지를 다 쓰는데

 

사용자 스타일이 젤 중요 > 그다음 제작자 스타일 > 그다음이 디폴트 스타일

 

2. 적용범위는 어디까지냐?

 

중요도가 같으면 스타일적용범위에 따라 우선순위정할 수 있는데

스타일 적용범위가 좁을수록

정확히 필요한 요소에만 적용한 스타일일수록

우선순위 높아져

 

스타일 규칙에다가..

!important 이렇게 붙여놓은애들은 다른애들보다 우선순위 높아져

적용범위에 따라 우선순위 높은거 나열한다면

 

!important > 인라인 스타일 > id스타일 > 클래스 스타일 > 타입 스타일

 

 

 

 

 

 

임포터!important가 없다면

타입스타일이랑 인라인 스타일 둘다 박아놨을 때 인라인스타일(HTML 태그 명령어 라인 내부에 스타일 정의)이 먼저뜨겠지!

 

 

웹문서에 사용되는 태그들은 서로 포함함

포함된 태그~

스타일 시트는 부모요소 속성들이 전달돼~ 감싸고 있다고~~

자식과 부모간의 성립된다는 가정 하에 부모태그에 스타일주면 자식에서 별도 적용하지 않으면 다 전달됨. 스타일 상속.

객체지향프로그래밍..

수업중에 나온 말인데 잘 모르겠어서 링크걸어둠..

 

<body>최상위 부모

바디는 웹문서 전체 적용이거를 잘 이용하면 동일 적용시에 잘 쓸수있음.

 

 

 

 

오른쪽 결과창

맨 마지막 숫자는 불투명도값!!

 

 

클릭하면 16진수/rgb/hsl 모드 바꿀 수 있음

 

 

 

텍스트 문단 정렬

 

 정렬 방법 지정하지 않으면 기본적으로 왼쪽 정렬이 된다.

 

 

줄간격을 원하는 만큼 조절할 수 있다

 line-height: 숫자px;

->간격조절하는 애
px말고 퍼센트도 가능!

문단정렬 조정

text-align 

 

text-shadow
text-transform
letter-spacing

word-spacing (잘안씀)

list-style-position

글자 간격조절 일반적으로 em 픽셀 퍼센트로 조절해~

 

padding

(위 오른쪽 아래 왼쪽 이렇게 설정값 읽힌다고 했음 링크눌러보면 뭔말하는지 알거야)

 

 

외부 / 기본형 / 내부 / 인라인 스타일 시트

 

 

 

 

쇼핑몰 만들기 (by선생님)

결과

<span>
HTML <span> 요소는 구문 콘텐츠를 위한 통용 인라인 컨테이너로, 본질적으로는 아무것도 나타내지 않습니다. 스타일을 적용하기 위해서, 또는 lang 등 어떤 특성의 값을 서로 공유하는 요소를 묶을 때 사용할 수 있습니다.
 적절한 의미를 가진 다른 요소가 없을 때에만 사용해야 합니다. 
<span>은 <div>와 매우 유사하지만, <div>는 블록 레벨 요소인 반면 <span>은 인라인 요소입니다.

 

 

 

이건 내가 만든 거

 

가운데 정렬해볼라고 이것저것 넣어봤는데

지금보니까 몇 개는 있으나 없으나 같네

내꺼 참고하면 안됨 배운거 일단 넣고 본게 많음,,

저 display:  쭉 있는거는

이미지를 가운데에 넣고자 margin: 0 auto; 넣어도 안되길래

인터넷이 알려준대로 넣어보니까 됐다...

 

 

박스모델: 웹문서의 내용을 박스 형태로 정의하는 방법

요 개념은 매우 자주 사용하므로 반드시 기억할 것

 

이 박스모델이 다 모여서 웹문서를 이룬다고 생각

마진, 페딩 테두리….css에서 빈번히 등장하는 개념

박스모델은 두가지 나열하는 방법이 있는데

요 개념은 매우 자주 사용하므로 반드시 기억할 것~

박스모델은 두가지 나열방법  두가지에 따라 나열 방법이 틀려져~~

 

1. 블록레벨 요소

태그를 사용해서 요소를 삽입했을 때 혼자 한 줄을 차지 하는 녀석

너비width 100프로라는 뜻

대표적인게 h1,div,p태그 등등

블록너비 요소에 왼쪽 오른쪽에 다른게 못들어온다는 뜻

이렇게 한 줄씩 먹고 있음

 

 

2. 인라인 레벨요소

 

2. 인라인레벨요소

한줄을 차지 하지 않는다.

콘텐츠 만큼만 영역을 차지하고 나머지 공간에는 다른 요소가 올 수 있다.

한줄에 인라인 레벨 요소들이 여러 개 올 수 있따!

예를 들어 스팸spam img strong…..

박스 크기 조정

콘텐츠와 콘텐츠 스타일 사이 여백 마진으로 둠. 

가로 와 세로 콘텐츠 영역, 크기 지정할 때 사용

여기서 부모는 바디body 의미함

 

오토라고 하면 콘텐츠 양에 따라 자동으로 지정된다~ 보통 오토 많이 넣기도 함. …

디폴트값. 안넣으면 지가 알아서 해줌 

여기에서 가로와 높이는 박스모델에서 콘텐츠 주변의 여백이나 테드리를 뺀 컨텐츠 영역의

크기 표시 (콘텐츠 여백은 20)

밑에 box하나 더만듦

 

웹문서에서 레이아웃구성할때는 css에서 박스모델 사용하는데

요소크기 쉽게 계산하려면 박스 사이징 속성을 보더박스로 지정해주는게 좋다

가운데 컨텐츠 영역/ 테두리. 마진은 없구

 

 

 

 

박스 사이징

 

웹문서에서 레이아웃구성할때는 css에서 박스모델 사용하는데

요소크기 쉽게 계산하려면 박스 사이징 속성을 보더박스로 지정해주는게 좋다

씨언어 시계방향 순서로 돌아(탑 라이트 바텀 레프트)

보더 테두리 스타일지정 해줌

 

탑 10픽셀 라이트 2픽셀

 

bordr-radius
모서리 둥글게!
(이미지도 만질 수 있음)

 

 

공부하면서 참고한 영상!

https://youtu.be/T7h8O7dpJIg

 

728x90

+ Recent posts