How can I configure the Http service adding headers to the call.
I try the following
class GlobalHttpHeaders {
static setup(Injector inj){
HttpDefaultHeaders http = inj.get(HttpDefaultHeaders);
http.setHeaders([{"X-Requested-With":"XMLHttpRequest"}], "COMMON");
}
}
And in the app the last line is:
Injector inj = ngBootstrap(module: new SiteIceiModule());
GlobalHttpHeaders.setup(inj);
But that don't work.
(I think) I got it working with:
#Injectable()
class MyDefaultHeaders extends HttpDefaultHeaders {
#override
setHeaders(Map<String, String> headers, String method) {
super.setHeaders(headers, method);
//if(method.toUpperCase() == 'POST') {
headers['X-Requested-With'] = 'XMLHttpRequest';
//}
}
}
#NgComponent(selector: 'my-comp', publishAs: 'ctrl', template:
'<div>My component</div>')
class MyComponent {
Http http;
MyComponent(this.http) {
//http.request('http://www.google.com/');
var h = http;
// debugger didn't show http so I filed https://code.google.com/p/dart/issues/detail?id=17486
Map m = {};
http.defaults.headers.setHeaders(m, 'GET');
print(m);
// prints:
// {Accept: application/json, text/plain, */*, X-Requested-With: XMLHttpRequest}
}
}
class MyAppModule extends Module {
MyAppModule() {
type(MyComponent);
type(HttpDefaultHeaders, implementedBy: MyDefaultHeaders);
init.createParser(this);
}
}
I couldn't examine http to verify the headers because the debugger didn't show me the field but as stated in the comment
when I apply headers.setHeaders do a map inside MyComponent I get my custom header (this is what Http does with headers)
I used DI 0.0.33, Angular 0.9.9
I'm a little late to the discussion, but the answer provided was not usable for me, as my http requests are made by a 3rd party library. But I figured out a way to change the default headers.
You can access and modify the HttpDefaultHeaders object like a map.
headers['Common'].addAll({'Authorization': 'Basic $auth', 'X-Testing': 'Testing'});
This also works with 3rd Party libraries like hammock.
Note: I used angular 1.1.1 I don't know in which version this was added.
Have you tried something like this:
class SiteIceiModule extends Module {
SiteIceiModule() {
// ...
factory(HttpDefaultHeaders, (inj) => inj.get(HttpDefaultHeaders)..setHeader({...}));
// ...
}
}
Related
I need to add a RequestInterceptor to a specific feign client. The interceptor will add auth information that I do not want to leak to a third party, hence I do not want it to trigger for ALL Feign clients. I have this working, but this seems a tad messy, and am hoping there is a cleaner (less code) option.
I am hoping someone can point to where I can simplify things. Particularly around the encoder/decoder stuff. I really dislike them cluttering up my services constructor like that and find it odd that they even need to be specified in the first place.
I have
// build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
I have a RequestInterceptor as
import feign.RequestInterceptor;
import feign.RequestTemplate;
public class BearerAuthRequestInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate requestTemplate) {
// ... SNIP ... (just adds an Authorization header)
}
}
I have a FeignClient as
#FeignClient(name = "myfeignclient")
public interface MyFeignClient {
#GetMapping(value = "/doTheThing")
String doTheThing();
}
I use my FeignClient from a service like so:
#Service
#Import(FeignClientsConfiguration.class)
public class MyService {
private final MyFeignClient myFeignClient;
#Autowired
public MyService(Decoder decoder, Encoder encoder, Contract contract) {
this.myFeignClient = Feign.builder()
.contract(contract)
.encoder(encoder)
.decoder(decoder)
.requestInterceptor(new BearerAuthRequestInterceptor())
.target(MyFeignClient.class, "https://whatever.com");
}
public void callTheFeignClient() {
myFeignClient.doTheThing();
}
}
Thanks to this comment, I managed to tidy up my implementation a little bit. So no more need for specifying encode/decoder nonsense, or having to manually build my Feign client.
The docs here provide some info, but as is typical they are a bit thin on concrete examples, so perhaps the below will help someone else. Note: I'm using spring boot, and including feign like so in build.gradle implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
First, create the RequestInterceptor like so:
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import feign.RequestInterceptor;
import lombok.extern.slf4j.Slf4j;
/**
* A Feign configuration to add the incoming Bearer token to an outgoing feign client request.
* Only annotate this class with "#Configuration" if you want this interceptor to apply globally to all your Feign clients.
* Otherwise you risk exposing the auth token to a third party, or adding it unnecessarily to requests that don't need it.
*/
#Slf4j
public class BearerAuthFeignConfig {
#Bean
public RequestInterceptor bearerAuthRequestInterceptor() {
return requestTemplate -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof Jwt) {
Jwt jwt = (Jwt) authentication.getPrincipal();
requestTemplate.header("Authorization", "Bearer " + jwt.getTokenValue());
} else {
log.error("Unable to add Authoriation header to Feign requestTemplate");
}
};
}
}
Then when declaring your feign client, pass the configuration
#FeignClient(
name = "my-client-that-needs-the-auth",
configuration = BearerAuthFeignConfig.class,
url = "http://whatever.com"
)
public interface PlayerManagementClient {
...
You'll also need the #EnableFeignClients annotation on your #SpringBootApplication class
How can i send data from client to server using html5 webcomponent
setting up data from server to client, is very easy, works like a charm
how ever cannot find solution to send data to server
Please assist, but Iam not going to use Lit or Polymer
#JavaScript
class SimpleComponent extends HtmlElement {
connectedCallback() {
this.innerHTML = '<input type="text" id="test"/>";
this._input = this.querySelector('#test');
this._input.onchange = function() {
***** i want to send the value to server ****
})
}
setInputValue(value) {
this._input.value = value;
}
}
customElements.define("simple-com",SimpleComponent);
Now Java at Server
#Tag("simple-com")
class SimpleComponent extends Component {
public SimpleComponent() {
}
public void setValue(String value) {
getElement().callJsFunction("setValue",value);
}
}
The main challenge compared to Polymer or LitElement is that an event handler defined using the pattern innerElement.onchange = function() {} will not be run with this referencing the custom element instance. This in turn means that trying to use this.$server won't work because this isn't pointing to the expected value even though $server is indeed present in the place where it's supposed to be.
The easiest way of fixing this is to change the code to use an arrow function (() => {}) instead of an explicit function. This works because arrow functions inherit this from the scope where the function is defined whereas explicit functions have this defined in different ways depending on how it is run. Another approach would be to store a reference to this in a separate variable (e.g. let root = this) and then reference that variable instead of this in the function (e.g root.$server.doSomething()).
Putting everything together, this is what the code looks like with my modifications to make everything work.
class SimpleComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = '<input type="text" id="test"/>';
this._input = this.querySelector('#test');
this._input.onchange = () => {
this.$server.handleChange(this._input.value);
};
}
setValue(value) {
this._input.value = value;
}
}
customElements.define("simple-com", SimpleComponent);
I was using JQuery for http requests to .NET controllers (I'm using .NET MVC 4.5.2), but am now starting to use Angular 2, so I want to handle those JQuery AJAX calls with Angular 2 instead. Here is the JQuery I was using before, which worked just like I wanted:
$.get('/Plan/Variety/ListVarietiesInMenuForSelling')
.done(function(data){
console.log(data)
});
How do I set up my Angular 2 service to accomplish the same thing? I've tried the code below:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class SellingMenuVarietiesService {
private url = '/Plan/Variety/ListVarietiesInMenuForSelling'; // URL to web api
constructor(private http: Http) { }
getVarieties() {
return this.http.get(this.url);
}
}
Unfortunately this doesn't work. Instead, I get this error in the console:
EXCEPTION: Uncaught (in promise): TypeError: Cannot read property '0' of undefined core.umd.js:3462
The only examples I've been able to find handle JSON data and then use Angular to parse the data and format it into HTML. My controller already returns the HTML I need, so I don't need Angular to parse JSON. How do I get the http request to work like it did when I was using JQuery?
Just to be clear, for testing purposes I changed return this.http.get(this.url); to return '<h1>test data</h1>'; and was able to get that to display correctly, so I know that the only issue is with the http request.
EDIT:
Here is the code where I call getVarieties():
export class SellingMenuVarietiesComponent implements OnInit {
varietyListSelling: any;
constructor(
private router: Router,
private sellingMenuVarietiesService: SellingMenuVarietiesService) { }
ngOnInit(): void {
this.varietyListSelling = this.sellingMenuVarietiesService.getVarieties();
console.log('initializing SellingMenuVarietiesComponent');
}
}
And here is how I bind it to the HTML:
<div [innerHtml]="varietyListSelling"></div>
I used that instead of {{varietyListSelling}} because I need the string to be converted to HTML.
UPDATE
I upgraded TypeScript and removed my InMemoryWebApiModule and InMemoryDataService imports from app.module.ts, which is resulting in a new error. The error now says: EXCEPTION: Unexpected token < in JSON at position 4
Is this because we are turning my HTML data into JSON? How can I just return the HTML like my JQuery was doing?
You could do something like this:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class SellingMenuVarietiesService {
private url = '/Plan/Variety/ListVarietiesInMenuForSelling'; // URL to web api
constructor(private http: Http) { }
public getVarieties(): Observable<any> {
return this.http.get(this.url).map(response=>{return response});
}
}
then to consume the service:
this.sellingMenuVarietiesService.getVarieties().subscribe(res => {
console.log(res);
});
Update:
The html you are trying to render is not rendering because the request has not completed when the template is being rendered. A possible solution for this is to add an ngIf to the div tag.
div *ngIf="varietyListSelling" [innerHtml]="varietyListSelling"></div>
You must subscribe to really send the request and read the response.
getVarieties() {
return this.http.get(this.url).map((response: Response) => {
return response.json();
},(error) => {
console.log(error);
//your want to implement your own error handling here.
});
}
And your component would look like
ngOnInit(): void {
this.sellingMenuVarietiesService.getVarieties().subscribe((res) => {
this.varietyListSelling = res;
});
console.log('initializing SellingMenuVarietiesComponent');
}
"Cannot find name 'Response'" and "Property 'map' does not exist on type 'Observable' I have same issue but it's not a problem , It show error .map but it's work.
I am having a component that has canactivate
import {isLoggedIn} from '../login/isLoginedIn';
#CanActivate((next, previous) => {
isLoggedIn()
})
My "isLoggedIn" is as below
import {Http, Headers} from 'angular2/http';
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
export const isLoggedIn = () => {
let injector = Injector.resolveAndCreate([Auth, Http]);
let auth = injector.get(Auth);
return auth.check();
};
I can't inject a service which has http as dependancy. Can this be done like this or is there a better way to do it?
Since the CanActivate is a decorator instead of a method as with OnActivate or CanDeactivate then you are correct in assuming that constructor dependency injection of the component that you are attempting to authorize is not an option.
The method which you are using will work, but there is a missed #Injectable() on your Auth class.
import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
#Injectable()
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
This approach is sound and I don't think that besides some syntactic sugar or minor refactoring that there would be much to improve this and still achieve the same amount of readability / maintainability for this approach.
One other addition that could be made to improve the flow and prevent a potential bug would be to return the observable in CanActivate so that the navigation will wait for the Http request to complete before deciding to continue or cancel.
#CanActivate((next, previous) => {
return isLoggedIn()
})
or for short
#CanActivate(() => isLoggedIn())
(Single statement arrow functions are auto-returning)
I'm using AngularDart for a new application of mine. I have a component set up like so:
#NgComponent(
selector: 'game-timeline',
templateUrl: '/static/dart/game/web/views/timelineview.html',
cssUrl: '/static/dart/game/web/views/timelineview.css',
publishAs: 'ctrl'
)
But my problem is, the template and css locations aren't necessarily known at build-time. They'll be on a CDN with a unique deploy-identifier on them. Something like...
http://cdn.domain.com/static/30294832098/dart/game/web/views/timelineview.html
And that number varies every deploy.
The path seems to be relative to the html page it's hosted on, which is not on the CDN, so I can't just use a relative path (../blah/blah)
I can inject a JS variable into the page telling me where the static root it, if that helps.
The main .dart/.js file is loaded from the CDN, but I can't seem to make it be relative to that.
Any ideas?
Update, here's my full solution adapted from pavelgj's great answer that reads in a js variable called STATIC_URL on the page.
import 'package:angular/angular.dart';
import 'package:js/js.dart' as js;
class CDNRewriter implements UrlRewriter {
String staticUrl;
CDNRewriter() {
var context = js.context;
staticUrl = js.context.STATIC_URL;
}
String call(String url) {
if (url.startsWith('/static/')) {
return _rewriteCdnUrl(url);
}
return url;
}
String _rewriteCdnUrl(String url) {
return url.replaceFirst(new RegExp(r'/static/'), staticUrl);
}
}
You can implement a custom UrlRewriter. UrlRewriter is called for all resources fetched via angular Http service, including templates and css.
class MyUrlRewriter implements UrlRewriter {
String call(String url) {
if (url.startsWith('/static/')) {
return _rewriteCdnUrl(url);
}
return url;
}
}
myModule.type(UrlRewriter, implementedBy: MyUrlRewriter);