"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > O - 개방형/폐쇄형 원칙(OCP)

O - 개방형/폐쇄형 원칙(OCP)

2024-11-08에 게시됨
검색:143

O - Open/Closed Principle (OCP)

What is Open/Closed Principle(OCP)?

According to the Open/Closed Principle, "Objects or entities (such as classes, modules, functions, etc.) should be open for extension but closed for modification when adding new features."

This means that software design should be structured in such a way that new features can be added without modifying the existing code. Modifying existing code can introduce new bugs or issues.

At first, this might seem a bit hard to grasp, but if we view it as a general approach rather than a strict rule, it makes more sense. It's important to remember that this principle originated in the 1990s, so it's less applicable now compared to back then.

The core goal of the Open/Closed Principle (OCP) is to encourage decoupling within the code, making the system easier to manage and reducing the risk of breaking existing functionality when adding new features or changes.

The term "decoupling" refers to "separating" or "keeping things separate." In software design, decoupling means designing different components or modules in such a way that they are less dependent on each other. In other words, changes in one component should not or should minimally affect other components. By implementing decoupling, software becomes more maintainable, scalable, and reusable.

Example 1:

Let's say our program has a feature for generating different types of reports. Currently, the program only supports PDF reports, but in the future, we may need to generate Excel or Word reports as well.

  • Before Adding New Features:
    If you've written code to generate PDF reports, it becomes a core part of the program. Now, if you want to add new report types, like Excel or Word reports, you may need to modify the existing code.

  • Following the Open/Closed Principle:
    To solve this problem, you can create an interface that defines the common behavior for generating reports. For example, a Report interface where the generateReport() method is defined.

JavaScript Code (Interface-like structure):

class Report {
    generateReport() {
        throw new Error("This method must be overridden");
    }
}
  • Create Two Classes for PDF and Excel Reports That Implement the Report Class:

JavaScript Code:

class PdfReport extends Report {
    generateReport() {
        console.log("Generating PDF Report");
    }
}

class ExcelReport extends Report {
    generateReport() {
        console.log("Generating Excel Report");
    }
}
  • Create a Factory Class to Return the Correct Report Class Based on the Report Type:

JavaScript Code:

class ReportFactory {
    static getReport(reportType) {
        if (reportType === "PDF") {
            return new PdfReport();
        } else if (reportType === "Excel") {
            return new ExcelReport();
        }
        throw new Error("Invalid report type");
    }
}

Use the Program to Generate Reports:
JavaScript Code:

// Example usage
const reportType = "Excel"; // This can be "PDF" or "Excel"
const report = ReportFactory.getReport(reportType);
report.generateReport();

Explanation:

  • Open/Closed Principle: To add a new report type, you simply need to implement the Report interface in a new class (e.g., WordReport) and add the new type to the factory class. This allows you to add new features without modifying the existing core code.

  • Decoupling: The logic for generating reports is separated from its usage. This creates a clear division between the main code and the report-generating classes, making it easier to add new features without changing the core code.

This example demonstrates how following the Open/Closed Principle leads to a flexible and scalable design.

Example 2:

Let's say we have a ShapeCalculator class that calculates the area and perimeter for different shapes. Currently, it only works for rectangles and circles. If we want to add a new shape, such as a triangle, we would have to modify the calculateArea and calculatePerimeter methods, which would violate the Open/Closed Principle (OCP).

Solution Following OCP:

We can create a base class Shape and then create separate concrete classes for each shape.

Step-by-Step Example:

  • Create a Base Class That Defines Common Methods for Different Shapes:

JavaScript Code:

class Shape {
    calculateArea() {
        throw new Error("Method 'calculateArea()' must be 
        implemented.");
    }

    calculatePerimeter() {
        throw new Error("Method 'calculatePerimeter()' must be 
        implemented.");
    }
}
  • Implement the Shape Class to Create Concrete Classes for Different Shapes:

JavaScript Code:

class Rectangle extends Shape {
    constructor(width, height) {
        super();
        this.width = width;
        this.height = height;
    }

    calculateArea() {
        return this.width * this.height;
    }

    calculatePerimeter() {
        return 2 * (this.width   this.height);
    }
}

class Circle extends Shape {
    constructor(radius) {
        super();
        this.radius = radius;
    }

    calculateArea() {
        return Math.PI * this.radius * this.radius;
    }

    calculatePerimeter() {
        return 2 * Math.PI * this.radius;
    }
}
  • The ShapeCalculator Class Can Work with Any Shape That Implements the Shape Interface: JavaScript Code:
class ShapeCalculator {
    static printDetails(shape) {
        console.log(`Area: ${shape.calculateArea()}`);
        console.log(`Perimeter: ${shape.calculatePerimeter()}`);
    }
}
  • Usage:

JavaScript Code:

// Creating instances of different shapes
const rectangle = new Rectangle(5, 10);
const circle = new Circle(7);

// Printing details of each shape
ShapeCalculator.printDetails(rectangle);
ShapeCalculator.printDetails(circle);

Explanation:

  • Open/Closed Principle: To add a new shape, you simply create a new class that implements the Shape interface, such as a Triangle class. There's no need to modify the ShapeCalculator class, as it can already work with any shape that implements the Shape interface.

  • Decoupling: There is a clear separation between the ShapeCalculator class and the shape classes. When adding a new shape type, you only need to create a new shape class that implements the Shape interface. This ensures that the code remains open for extension (new shapes can be added) but closed for modification (existing code doesn’t need to be changed).

This design ensures that your code follows the Open/Closed Principle and maintains code stability by not requiring changes to the existing code when new features are added.

Example 3:

Suppose you're developing a web app where you need to convert decimal numbers to binary. Initially, you create a DecimalToBinary class to handle this conversion:

JavaScript Code:

class DecimalToBinary {
  // Other helper functions...
  dec2bin(number) {
    return parseInt(number, 10).toString(2);
  }
}

Now, if you suddenly need to add conversions from binary to decimal or decimal to hexadecimal, you might be tempted to modify the DecimalToBinary class. However, doing so would violate the Open/Closed Principle (OCP).

Solution:

To adhere to OCP, we should design the class with future changes in mind, without modifying existing code.

Step-by-Step Solution:

JavaScript Code:

class NumberConverter {
  isNumber(number) {
    // Example helper function
    return true;
  }

  convertBase(number, fromBase, toBase) {
    // A simple (naive) implementation, without error checking
    return parseInt(number, fromBase).toString(toBase);
  }
}

class DecimalToBinary extends NumberConverter {
  isDecimalNumber(number) {
    // Example helper function, not the actual implementation
    return true;
  }

  dec2bin(number) {
    return this.convertBase(number, 10, 2);
  }
}

class BinaryToDecimal extends NumberConverter {
  isBinaryNumber(number) {
    // Example helper function, not the actual implementation
    return true;
  }

  bin2dec(number) {
    return this.convertBase(number, 2, 10);
  }
}

Explanation:

  • Base Class (NumberConverter):
    We created a base class, NumberConverter, that contains a common convertBase method. This method can convert numbers from one base to another.

  • Derived Classes (DecimalToBinary, BinaryToDecimal):
    Next, we created two specific classes, DecimalToBinary and BinaryToDecimal, that inherit from NumberConverter. These classes handle specific conversions without modifying the base class.

OCP Application:

With this design, you can add new conversion functions, such as DecimalToHexadecimal or HexadecimalToBinary, without modifying any existing code. This ensures that your code is open for extension (adding new features) but closed for modification (not altering existing code).

This design adheres to the Open/Closed Principle, allowing your code to be extended easily while maintaining its existing functionality.

O - Open/Closed Principle (OCP) in React

React is a library mainly used for building UI components, and it follows the Open/Closed Principle (OCP), allowing developers to extend the functionality of components without modifying their source code. This is primarily achieved through composition of components.

Importance of OCP in React:

When building applications with React, developers aim to write reusable, modular, and maintainable code. The Open/Closed Principle (OCP) plays a crucial role in achieving these goals.

Let's break down why OCP is important in React:

  1. Code Reusability: By following OCP, we can extend a component's functionality without changing its original implementation. This allows us to reuse the same component in different places, reducing code duplication and simplifying development.

  2. Ease of Maintenance: If we can add new features to a component without modifying its original code, maintenance becomes easier. Since we don't touch the old code, there's less risk of introducing new bugs, and the stability of the application increases.

  3. Decoupling: OCP encourages us to decouple components from each other. This means we can change or extend the behavior of one component without creating unnecessary dependencies on other components. It simplifies the system's complexity and makes adding new features easier.

  4. Easier Testing: When components are designed to follow OCP, they are separated into smaller, independent units. This makes it easier to test them in isolation, speeding up bug identification and resolution.

  5. Faster Development: By adhering to OCP, developers can quickly add new features, as they don't have to worry about breaking existing code. This allows for faster iteration and helps bring new ideas or features into production more quickly.

Thus, OCP in React is essential because it promotes code reusability, simplifies maintenance, ensures decoupling, facilitates easier testing, and encourages faster development.

Example 1:

Extending a Button Component Without Modifying It
Below is an example where we create a Button component, which is simple and reusable. Later, we create a new IconButton component that uses the Button component but adds a new feature (an icon) without modifying the original Button component.

JavaScript Code:

// Button.js
const Button = ({ label, onClick }) => (
  
);

// IconButton.js
const IconButton = ({ icon, label, onClick }) => (
  
);

Explanation:

  • Button Component: The Button component is a simple button that takes a label and an onClick event handler. This is a general, reusable component that can be easily used in other places.

  • IconButton Component: The IconButton component builds on top of the Button component by adding an icon (icon) without changing the original Button component. It extends the functionality while keeping the original component intact.

Why This Is Important?

This example follows OCP because we added a new feature (an icon) without changing the original Button component's code. This approach helps maintain the stability of the codebase while making it easier to introduce new features.

Example 2:

Extending Component Functionality with Custom Hooks
In React, Custom Hooks provide a powerful way to add new functionality to components without changing their core logic. Custom Hooks are essentially functions that make React's state and lifecycle management logic reusable. This approach follows the Open/Closed Principle (OCP), where new functionality can be added without modifying the existing code.

JavaScript Code:

// useUserData.js
const useUserData = () => {
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    // Fetch and set user data
    // You can add API fetching logic here
    setUserData({ name: "John Doe" }); // Example data
  }, []);

  return userData;
};

// UserProfile.js
const UserProfile = () => {
  const userData = useUserData();
  return 
{userData?.name}
; };

Explanation:

  • useUserData Custom Hook:

The useUserData hook is responsible for managing the user data. It uses useState to handle state and useEffect for side effects, such as fetching data from an API.
It fetches and sets user data, which can be reused across multiple components that need to manage user information.

  • UserProfile Component:

The UserProfile component uses the useUserData hook to display the user's name. The component itself remains simple and focuses only on rendering, while the logic for fetching and managing user data is abstracted into the custom hook.

Why This Is Important?

By using Custom Hooks, you can add new functionality (e.g., fetching user data) to a component without modifying its core structure. This adheres to the Open/Closed Principle (OCP) in React, as you can extend the functionality of your application by creating reusable hooks without altering the original component logic.

Key Benefits of Using Custom Hooks:

Custom Hooks allow you to reuse logic across multiple components, making your code more modular and maintainable.
Separation of Concerns:

By moving logic such as data fetching or state management into hooks, your components can focus solely on rendering, improving readability and reducing complexity.

Example 3:

Using Higher-Order Components (HOCs) to Extend Functionality
In React, Higher-Order Components (HOCs) provide a way to add new functionality to components without modifying the existing component. HOCs follow the Open/Closed Principle (OCP) by allowing you to extend or modify component behavior while keeping the original component unchanged.

Scenario:
We have a simple Button component that just renders a button. We want to add logging functionality to this button (i.e., log some information when it’s clicked) without changing the original Button component. We'll achieve this using an HOC.

  • The Original Button Component JavaScript code:
// Button.js
import React from 'react';

const Button = ({ label, onClick }) => (
  
);

export default Button;
  • Creating the HOC (withLogging) JavaScript code:
// withLogging.js
import React from 'react';

const withLogging = (WrappedComponent) => {
  return (props) => {
    const handleClick = (event) => {
      console.log(`Button with label "${props.label}" was clicked.`);
      if (props.onClick) {
        props.onClick(event);
      }
    };

    return ;
  };
};

export default withLogging;
  • Creating the New Component with the HOC JavaScript code:
// LoggingButton.js
import React from 'react';
import Button from './Button';
import withLogging from './withLogging';

const LoggingButton = withLogging(Button);

export default LoggingButton;
  • Usage in the App Component JavaScript code:
// App.js
import React from 'react';
import LoggingButton from './LoggingButton';

const App = () => {
  const handleButtonClick = () => {
    alert('Button clicked!');
  };

  return (
    

OCP Example with HOC in React

); }; export default App;

Explanation:

  • Button Component:
    The Button component is a simple, reusable component that renders a button and takes label and onClick as props.

  • HOC (withLogging):
    The withLogging function is an HOC that takes a component (WrappedComponent) as an argument and returns a new component with added functionality.

In this case, it adds a handleClick function that logs a message when the button is clicked, and then invokes the original onClick handler (if provided).

The HOC spreads all the original props (...props) to the wrapped component but overrides the onClick handler.

  • LoggingButton Component:

LoggingButton is a new version of the Button component that has logging functionality, created using the withLogging HOC.

When this component is used, it logs a message when the button is clicked and then calls the original click handler.

  • Usage in App:

In the App component, we render the LoggingButton. When the button is clicked, it first logs the message and then displays an alert, demonstrating the combined functionalities of logging and handling the button click.

Why This Is Important?

  • Code Reusability: Using HOCs, you can add the same functionality (like logging) to multiple components without duplicating code.

  • Code Stability: The original Button component remains unchanged, and new functionality is added without modifying the core logic, adhering to the Open/Closed Principle (OCP).

  • Decoupling: Features like logging can be kept separate from the core logic of the Button, making the system more modular and easier to maintain.

  • Scalability: In large-scale applications, adding new features becomes easier, as existing components can be extended without changing them.

Conclusion:

This example demonstrates how Higher-Order Components (HOCs) can be used to follow the Open/Closed Principle in React, allowing you to add new features without modifying existing components. This approach enhances code stability, reusability, and maintainability.

Disadvantages of the Open/Closed Principle(OCP)

While the Open/Closed Principle (OCP) is a valuable guideline in software development, it has several limitations that can pose challenges when applying it. Here are some of the key drawbacks:

  • Increased Design Complexity:

Adhering to the OCP often requires the use of abstractions (like abstract classes and interfaces) and design patterns. While these abstractions help encapsulate common behaviors for future extension, they can also make the codebase more complex.
This complexity may lead to difficulties in understanding and maintaining the code. Team members may spend additional time deciphering intricate structures rather than focusing on functionality. Thus, while following OCP is beneficial, it can sometimes make code unnecessarily complicated.
It raises the question of whether such abstractions are truly necessary or if simpler solutions could suffice.

  • Reusability vs Complexity:

In the pursuit of increasing code reusability, excessive abstractions can complicate the codebase. Complex code can be harder to maintain, increasing the likelihood of bugs and errors. The balance between reusability and complexity must be carefully managed. too much focus on reusability may lead to convoluted code that detracts from clarity and maintainability.

  • Anticipating Future Changes:

Designing code according to OCP often requires anticipating all potential future changes in the system. However, in practical development, it’s impossible to predict every change accurately. This leads to extended design phases, consuming additional time and resources as developers try to foresee all possibilities.

  • Code Overhead:

Following OCP typically results in the creation of new classes or modules, which can introduce additional overhead in the codebase. This overhead can impact system performance and slow down the development process, as developers have to manage more files and components.

  • Testing and Debugging Complexity:

The use of abstractions and design patterns complicates testing and debugging. The presence of dependencies across different layers or components can make it challenging to identify and resolve issues. Developers may find it more difficult to write effective unit tests or track down bugs when dealing with a complex hierarchy of components.

Conclusion

Given these limitations, it’s crucial to consider the requirements and context when applying the Open/Closed Principle. Following OCP is not always mandatory; rather, it should serve as a guideline aimed at enhancing code stability and reusability.

In summary, while the OCP is particularly important in UI libraries like React, as it fosters more modular, reusable, and maintainable components, it is essential to strike a balance between adhering to principles and maintaining clarity in the codebase. Understanding when to apply OCP, and when simpler approaches might be sufficient, is key to effective software design.

릴리스 선언문 이 글은 https://dev.to/nozibul_islam_113b1d5334f/o-openclosed-principle-ocp-g3l?1 에서 복제되었습니다.1 침해 내용이 있는 경우, [email protected]으로 연락하여 삭제하시기 바랍니다.
최신 튜토리얼 더>
  • gRPC: 어디 사세요? 무엇을 먹나요?
    gRPC: 어디 사세요? 무엇을 먹나요?
    A primeira vez que ouvi falar sobre RPC foi em uma aula de sistema distribuídos, ainda quando estava cursando a graduação em Ciência da Computação. Ac...
    프로그램 작성 2024-11-08에 게시됨
  • 3D 모델에 대한 부드러운 접선 공간 법선을 어떻게 얻을 수 있습니까?
    3D 모델에 대한 부드러운 접선 공간 법선을 어떻게 얻을 수 있습니까?
    부드러운 접선 공간 법선을 달성하는 방법접선, 종법선, 및 법선 벡터를 사용하는 경우 모델의 사전 제공된 법선을 고려하는 것이 중요합니다.정점당 법선 평균첫 번째 접근 방식은 면당 법선과 법선을 계산하는 것입니다. 면을 형성하는 꼭지점에 분포합니다. 각 정점은 초기에 ...
    프로그램 작성 2024-11-08에 게시됨
  • 간단한 예제를 통해 JavaScript의 호출, 적용 및 바인딩 이해
    간단한 예제를 통해 JavaScript의 호출, 적용 및 바인딩 이해
    간단한 예제를 통해 JavaScript의 호출, 적용 및 바인딩 이해 JavaScript로 작업할 때 호출, 적용, 바인딩이라는 세 가지 강력한 방법을 접할 수 있습니다. 이러한 메서드는 함수에서 this의 값을 제어하는 ​​데 사용되어 개체 작업을 더...
    프로그램 작성 2024-11-08에 게시됨
  • 중괄호 배치가 JavaScript 실행에 어떤 영향을 미치나요?
    중괄호 배치가 JavaScript 실행에 어떤 영향을 미치나요?
    중괄호 배치 및 JavaScript 실행JavaScript에서 중괄호 배치는 코드의 동작과 출력을 크게 변경할 수 있습니다. 제공된 코드 조각에서 볼 수 있듯이 중괄호 배치를 한 번만 변경해도 결과가 크게 달라질 수 있습니다.자동 세미콜론 삽입 및 정의되지 않은 반환여...
    프로그램 작성 2024-11-08에 게시됨
  • Elasticsearch 알아보기
    Elasticsearch 알아보기
    Elasticsearch는 Apache Lucene 라이브러리를 기반으로 구축된 강력한 오픈 소스 검색 및 분석 엔진입니다. 대용량 데이터를 처리하고 복잡한 검색을 효율적으로 수행하도록 설계되었습니다. Elasticsearch의 주요 기능은 다음과 같습니다: 분산 아키...
    프로그램 작성 2024-11-08에 게시됨
  • 배당률: Python 기반 금융 프로젝트의 중요한 지표
    배당률: Python 기반 금융 프로젝트의 중요한 지표
    배당률: Python 기반 금융 프로젝트의 중요한 지표 재무 분석 영역에서 배당금은 많은 투자자들에게 매우 중요합니다. 특히 재무 데이터를 처리하거나 투자 전략을 자동화하는 Python 프로젝트를 개발하는 경우 배당률을 계산하고 분석하는 것이 핵심 요소...
    프로그램 작성 2024-11-08에 게시됨
  • 병렬 또는 분산 테스트를 통해 여러 브라우저에서 WebUI 기능 파일을 실행하는 방법은 무엇입니까?
    병렬 또는 분산 테스트를 통해 여러 브라우저에서 WebUI 기능 파일을 실행하는 방법은 무엇입니까?
    병렬 또는 분산 테스트를 사용하여 여러 브라우저에서 WebUI 기능 파일 실행병렬 테스트를 사용하여 여러 브라우저(Zalenium)에 대해 WebUI 기능 파일을 실행하려면 실행기 또는 분산 테스트의 경우 다음 접근 방식을 활용합니다.병렬 실행기 및 시나리오 개요:시나...
    프로그램 작성 2024-11-08에 게시됨
  • SOAP와 REST API: 주요 차이점 이해
    SOAP와 REST API: 주요 차이점 이해
    웹 서비스 세계에서 SOAP(Simple Object Access Protocol)와 REST(Representational State Transfer)는 널리 사용되는 두 가지(Soap 대 Rest API) 아키텍처입니다. 둘 다 시스템 간의 통신 프로토콜 역할을 ...
    프로그램 작성 2024-11-08에 게시됨
  • CSS로 텍스트 밑줄 색상을 사용자 정의하는 방법은 무엇입니까?
    CSS로 텍스트 밑줄 색상을 사용자 정의하는 방법은 무엇입니까?
    CSS를 사용하여 텍스트 밑줄 색상 사용자 정의웹 디자인에서 텍스트에 밑줄을 추가하는 것은 정보를 강조하거나 강조하는 일반적인 방법입니다. 하지만 밑줄 색상을 변경하여 독특한 느낌을 더하고 싶다면 어떻게 해야 할까요? 가능합니까?예, CSS를 사용하여 텍스트 아래 줄의...
    프로그램 작성 2024-11-08에 게시됨
  • JavaScript로 클릭재킹 방어 기술 구현
    JavaScript로 클릭재킹 방어 기술 구현
    클릭재킹과 같은 정교한 공격의 출현으로 인해 보안이 오늘날 온라인 세계의 주요 문제가 되었습니다. 공격자는 소비자가 처음에 본 것과 다른 것을 클릭하도록 속임으로써 비참한 결과를 초래할 수 있는 "클릭재킹"이라는 사악한 방법을 배포합니다. 이러한 종류...
    프로그램 작성 2024-11-08에 게시됨
  • 플로팅된 Div가 후속 Div의 크기를 조정하지 않는 이유는 무엇입니까?
    플로팅된 Div가 후속 Div의 크기를 조정하지 않는 이유는 무엇입니까?
    Float 크기가 조정되지 않는 Div의 미스터리CSS float를 사용할 때 후속 요소가 새 요소로 흘러가는 대신 왼쪽에 정렬된다고 가정합니다. 선. 그러나 제공된 예시와 같은 일부 시나리오에서는 다음 div가 첫 번째 div의 오른쪽에서 시작하는 대신 계속해서 전체...
    프로그램 작성 2024-11-08에 게시됨
  • PYTHON을 사용하여 MySQL로 데이터 가져오기
    PYTHON을 사용하여 MySQL로 데이터 가져오기
    소개 특히 테이블 수가 많은 경우 데이터베이스로 데이터를 수동으로 가져오는 것은 번거로울 뿐만 아니라 시간도 많이 소요됩니다. Python 라이브러리를 사용하면 더 쉽게 만들 수 있습니다. kaggle에서 그림 데이터세트를 다운로드하세요. 그림 데이터 ...
    프로그램 작성 2024-11-08에 게시됨
  • 필수 MySQL 연산자 및 해당 애플리케이션
    필수 MySQL 연산자 및 해당 애플리케이션
    MySQL 연산자는 정확한 데이터 조작 및 분석을 가능하게 하는 개발자를 위한 핵심 도구입니다. 값 할당, 데이터 비교 및 ​​복잡한 패턴 일치를 포함한 다양한 기능을 다룹니다. JSON 데이터를 처리하든 조건에 따라 레코드를 필터링하든 효율적인 데이터베이스 관리를 위...
    프로그램 작성 2024-11-08에 게시됨
  • 크론 작업 테스트 방법: 전체 가이드
    크론 작업 테스트 방법: 전체 가이드
    Cron 작업은 작업 예약, 프로세스 자동화, 지정된 간격으로 스크립트 실행을 위한 많은 시스템에서 필수적입니다. 웹 서버를 유지 관리하든, 백업을 자동화하든, 일상적인 데이터 가져오기를 실행하든 크론 작업은 작업을 원활하게 실행합니다. 그러나 다른 자동화된 작업과 ...
    프로그램 작성 2024-11-08에 게시됨
  • Next.js 미들웨어 소개: 예제와 함께 작동하는 방법
    Next.js 미들웨어 소개: 예제와 함께 작동하는 방법
    Nextjs의 라우팅에 대해 이야기해 보겠습니다. 오늘은 가장 강력한 미들웨어 중 하나에 대해 이야기해보겠습니다. Nextjs의 미들웨어는 서버의 요청을 가로채고 요청 흐름(리디렉션, URL 재작성)을 제어하고 인증, 헤더, 쿠키 지속성과 같은 기능을 전체적으로 향상시...
    프로그램 작성 2024-11-08에 게시됨

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3