docs(aio): Fix http guide
This commit is contained in:
parent
ddc286f4b5
commit
7e95e2b0ba
@ -29,7 +29,7 @@ import {HttpClientModule} from '@angular/common/http';
|
|||||||
export class MyAppModule {}
|
export class MyAppModule {}
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you import `HttpClientModule` into your app module, you can inject `HttpClient`
|
Once you import `HttpClientModule` into your app module, you can inject `HttpClient`
|
||||||
into your components and services.
|
into your components and services.
|
||||||
|
|
||||||
## Making a request for JSON data
|
## Making a request for JSON data
|
||||||
@ -56,7 +56,7 @@ export class MyComponent implements OnInit {
|
|||||||
|
|
||||||
// Inject HttpClient into your component or service.
|
// Inject HttpClient into your component or service.
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// Make the HTTP request:
|
// Make the HTTP request:
|
||||||
this.http.get('/api/items').subscribe(data => {
|
this.http.get('/api/items').subscribe(data => {
|
||||||
@ -72,7 +72,7 @@ export class MyComponent implements OnInit {
|
|||||||
|
|
||||||
In the above example, the `data['results']` field access stands out because you use bracket notation to access the results field. If you tried to write `data.results`, TypeScript would correctly complain that the `Object` coming back from HTTP does not have a `results` property. That's because while `HttpClient` parsed the JSON response into an `Object`, it doesn't know what shape that object is.
|
In the above example, the `data['results']` field access stands out because you use bracket notation to access the results field. If you tried to write `data.results`, TypeScript would correctly complain that the `Object` coming back from HTTP does not have a `results` property. That's because while `HttpClient` parsed the JSON response into an `Object`, it doesn't know what shape that object is.
|
||||||
|
|
||||||
You can, however, tell `HttpClient` what type the response will be, which is recommended.
|
You can, however, tell `HttpClient` what type the response will be, which is recommended.
|
||||||
To do so, first you define an interface with the correct shape:
|
To do so, first you define an interface with the correct shape:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@ -163,7 +163,7 @@ RxJS has a useful operator called `.retry()`, which automatically resubscribes t
|
|||||||
|
|
||||||
First, import it:
|
First, import it:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import 'rxjs/add/operator/retry';
|
import 'rxjs/add/operator/retry';
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -197,7 +197,7 @@ In addition to fetching data from the server, `HttpClient` supports mutating req
|
|||||||
|
|
||||||
### Making a POST request
|
### Making a POST request
|
||||||
|
|
||||||
One common operation is to POST data to a server; for example when submitting a form. The code for
|
One common operation is to POST data to a server; for example when submitting a form. The code for
|
||||||
sending a POST request is very similar to the code for GET:
|
sending a POST request is very similar to the code for GET:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@ -261,12 +261,12 @@ The above sections detail how to use the basic HTTP functionality in `@angular/c
|
|||||||
|
|
||||||
### Intercepting all requests or responses
|
### Intercepting all requests or responses
|
||||||
|
|
||||||
A major feature of `@angular/common/http` is _interception_, the ability to declare interceptors which sit in between your application and the backend. When your application makes a request, interceptors transform it
|
A major feature of `@angular/common/http` is _interception_, the ability to declare interceptors which sit in between your application and the backend. When your application makes a request, interceptors transform it
|
||||||
before sending it to the server, and the interceptors can transform the response on its way back before your application sees it. This is useful for everything from authentication to logging.
|
before sending it to the server, and the interceptors can transform the response on its way back before your application sees it. This is useful for everything from authentication to logging.
|
||||||
|
|
||||||
#### Writing an interceptor
|
#### Writing an interceptor
|
||||||
|
|
||||||
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
|
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
|
||||||
has a single `intercept()` method. Here is a simple interceptor which does nothing but forward the request through without altering it:
|
has a single `intercept()` method. Here is a simple interceptor which does nothing but forward the request through without altering it:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@ -319,7 +319,7 @@ An interceptor must pass through all events that it does not understand or inten
|
|||||||
|
|
||||||
##### Ordering
|
##### Ordering
|
||||||
|
|
||||||
When you provide multiple interceptors in an application, Angular applies them in the order that you
|
When you provide multiple interceptors in an application, Angular applies them in the order that you
|
||||||
provided them.
|
provided them.
|
||||||
|
|
||||||
##### Immutability
|
##### Immutability
|
||||||
@ -335,10 +335,10 @@ If you have a need to mutate the request body, you need to copy the request body
|
|||||||
Since requests are immutable, they cannot be modified directly. To mutate them, use `clone()`:
|
Since requests are immutable, they cannot be modified directly. To mutate them, use `clone()`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpError<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// This is a duplicate. It is exactly the same as the original.
|
// This is a duplicate. It is exactly the same as the original.
|
||||||
const dupReq = req.clone();
|
const dupReq = req.clone();
|
||||||
|
|
||||||
// Change the URL and replace 'http://' with 'https://'
|
// Change the URL and replace 'http://' with 'https://'
|
||||||
const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
|
const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/com
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthInterceptor implements HttpInterceptor {
|
export class AuthInterceptor implements HttpInterceptor {
|
||||||
constructor(private auth: AuthService) {}
|
constructor(private auth: AuthService) {}
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// Get the auth header from the service.
|
// Get the auth header from the service.
|
||||||
const authHeader = this.auth.getAuthorizationHeader();
|
const authHeader = this.auth.getAuthorizationHeader();
|
||||||
@ -390,7 +390,7 @@ import 'rxjs/add/operator/do';
|
|||||||
|
|
||||||
export class TimingInterceptor implements HttpInterceptor {
|
export class TimingInterceptor implements HttpInterceptor {
|
||||||
constructor(private auth: AuthService) {}
|
constructor(private auth: AuthService) {}
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
const started = Date.now();
|
const started = Date.now();
|
||||||
return next
|
return next
|
||||||
@ -398,7 +398,7 @@ export class TimingInterceptor implements HttpInterceptor {
|
|||||||
.do(event => {
|
.do(event => {
|
||||||
if (event instanceof HttpResponse) {
|
if (event instanceof HttpResponse) {
|
||||||
const elapsed = Date.now() - started;
|
const elapsed = Date.now() - started;
|
||||||
console.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
|
console.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -416,7 +416,7 @@ abstract class HttpCache {
|
|||||||
* Returns a cached response, if any, or null if not present.
|
* Returns a cached response, if any, or null if not present.
|
||||||
*/
|
*/
|
||||||
abstract get(req: HttpRequest<any>): HttpResponse<any>|null;
|
abstract get(req: HttpRequest<any>): HttpResponse<any>|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds or updates the response in the cache.
|
* Adds or updates the response in the cache.
|
||||||
*/
|
*/
|
||||||
@ -430,14 +430,14 @@ An interceptor can apply this cache to outgoing requests.
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class CachingInterceptor implements HttpInterceptor {
|
export class CachingInterceptor implements HttpInterceptor {
|
||||||
constructor(private cache: HttpCache) {}
|
constructor(private cache: HttpCache) {}
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// Before doing anything, it's important to only cache GET requests.
|
// Before doing anything, it's important to only cache GET requests.
|
||||||
// Skip this interceptor if the request method isn't GET.
|
// Skip this interceptor if the request method isn't GET.
|
||||||
if (req.method !== 'GET') {
|
if (req.method !== 'GET') {
|
||||||
return next.handle(req);
|
return next.handle(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, check the cache to see if this request exists.
|
// First, check the cache to see if this request exists.
|
||||||
const cachedResponse = this.cache.get(req);
|
const cachedResponse = this.cache.get(req);
|
||||||
if (cachedResponse) {
|
if (cachedResponse) {
|
||||||
@ -445,7 +445,7 @@ export class CachingInterceptor implements HttpInterceptor {
|
|||||||
// the request to the next handler.
|
// the request to the next handler.
|
||||||
return Observable.of(cachedResponse);
|
return Observable.of(cachedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No cached response exists. Go to the network, and cache
|
// No cached response exists. Go to the network, and cache
|
||||||
// the response when it arrives.
|
// the response when it arrives.
|
||||||
return next.handle(req).do(event => {
|
return next.handle(req).do(event => {
|
||||||
@ -469,17 +469,17 @@ intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
|
|||||||
if (req.method !== 'GET') {
|
if (req.method !== 'GET') {
|
||||||
return next.handle(req);
|
return next.handle(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be an Observable of the cached value if there is one,
|
// This will be an Observable of the cached value if there is one,
|
||||||
// or an empty Observable otherwise. It starts out empty.
|
// or an empty Observable otherwise. It starts out empty.
|
||||||
let maybeCachedResponse: Observable<HttpEvent<any>> = Observable.empty();
|
let maybeCachedResponse: Observable<HttpEvent<any>> = Observable.empty();
|
||||||
|
|
||||||
// Check the cache.
|
// Check the cache.
|
||||||
const cachedResponse = this.cache.get(req);
|
const cachedResponse = this.cache.get(req);
|
||||||
if (cachedResponse) {
|
if (cachedResponse) {
|
||||||
maybeCachedResponse = Observable.of(cachedResponse);
|
maybeCachedResponse = Observable.of(cachedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an Observable (but don't subscribe) that represents making
|
// Create an Observable (but don't subscribe) that represents making
|
||||||
// the network request and caching the value.
|
// the network request and caching the value.
|
||||||
const networkResponse = next.handle(req).do(event => {
|
const networkResponse = next.handle(req).do(event => {
|
||||||
@ -488,7 +488,7 @@ intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
|
|||||||
this.cache.put(req, event);
|
this.cache.put(req, event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now, combine the two and send the cached response first (if there is
|
// Now, combine the two and send the cached response first (if there is
|
||||||
// one), and the network response second.
|
// one), and the network response second.
|
||||||
return Observable.concat(maybeCachedResponse, networkResponse);
|
return Observable.concat(maybeCachedResponse, networkResponse);
|
||||||
@ -509,7 +509,7 @@ const req = new HttpRequest('POST', '/upload/file', file, {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
This option enables tracking of progress events. Remember, every progress event triggers
|
This option enables tracking of progress events. Remember, every progress event triggers
|
||||||
change detection, so only turn them on if you intend to actually update the UI on each event.
|
change detection, so only turn them on if you intend to actually update the UI on each event.
|
||||||
|
|
||||||
Next, make the request through the `request()` method of `HttpClient`. The result will be an Observable of events, just like with interceptors:
|
Next, make the request through the `request()` method of `HttpClient`. The result will be an Observable of events, just like with interceptors:
|
||||||
@ -532,11 +532,11 @@ http.request(req).subscribe(event => {
|
|||||||
|
|
||||||
[Cross-Site Request Forgery (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website. `HttpClient` supports a [common mechanism](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token) used to prevent XSRF attacks. When performing HTTP requests, an interceptor reads a token from a cookie, by default `XSRF-TOKEN`, and sets it as an HTTP header, `X-XSRF-TOKEN`. Since only code that runs on your domain could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
|
[Cross-Site Request Forgery (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website. `HttpClient` supports a [common mechanism](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token) used to prevent XSRF attacks. When performing HTTP requests, an interceptor reads a token from a cookie, by default `XSRF-TOKEN`, and sets it as an HTTP header, `X-XSRF-TOKEN`. Since only code that runs on your domain could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
|
||||||
|
|
||||||
By default, an interceptor sends this cookie on all mutating requests (POST, etc.)
|
By default, an interceptor sends this cookie on all mutating requests (POST, etc.)
|
||||||
to relative URLs but not on GET/HEAD requests or
|
to relative URLs but not on GET/HEAD requests or
|
||||||
on requests with an absolute URL.
|
on requests with an absolute URL.
|
||||||
|
|
||||||
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication
|
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication
|
||||||
cookie with a salt for added security.
|
cookie with a salt for added security.
|
||||||
|
|
||||||
In order to prevent collisions in environments where multiple Angular apps share the same domain or subdomain, give each application a unique cookie name.
|
In order to prevent collisions in environments where multiple Angular apps share the same domain or subdomain, give each application a unique cookie name.
|
||||||
@ -598,21 +598,21 @@ it('expects a GET request', inject([HttpClient, HttpTestingController], (http: H
|
|||||||
http
|
http
|
||||||
.get('/data')
|
.get('/data')
|
||||||
.subscribe(data => expect(data['name']).toEqual('Test Data'));
|
.subscribe(data => expect(data['name']).toEqual('Test Data'));
|
||||||
|
|
||||||
// At this point, the request is pending, and no response has been
|
// At this point, the request is pending, and no response has been
|
||||||
// sent. The next step is to expect that the request happened.
|
// sent. The next step is to expect that the request happened.
|
||||||
const req = httpMock.expectOne('/data');
|
const req = httpMock.expectOne('/data');
|
||||||
|
|
||||||
// If no request with that URL was made, or if multiple requests match,
|
// If no request with that URL was made, or if multiple requests match,
|
||||||
// expectOne() would throw. However this test makes only one request to
|
// expectOne() would throw. However this test makes only one request to
|
||||||
// this URL, so it will match and return a mock request. The mock request
|
// this URL, so it will match and return a mock request. The mock request
|
||||||
// can be used to deliver a response or make assertions against the
|
// can be used to deliver a response or make assertions against the
|
||||||
// request. In this case, the test asserts that the request is a GET.
|
// request. In this case, the test asserts that the request is a GET.
|
||||||
expect(req.request.method).toEqual('GET');
|
expect(req.request.method).toEqual('GET');
|
||||||
|
|
||||||
// Next, fulfill the request by transmitting a response.
|
// Next, fulfill the request by transmitting a response.
|
||||||
req.flush({name: 'Test Data'});
|
req.flush({name: 'Test Data'});
|
||||||
|
|
||||||
// Finally, assert that there are no outstanding requests.
|
// Finally, assert that there are no outstanding requests.
|
||||||
httpMock.verify();
|
httpMock.verify();
|
||||||
}));
|
}));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user